• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
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.
13  *
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.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ***************************************************************************/
22 
23 #include "curl_setup.h"
24 
25 #ifndef CURL_DISABLE_TELNET
26 
27 #ifdef HAVE_NETINET_IN_H
28 #include <netinet/in.h>
29 #endif
30 #ifdef HAVE_NETDB_H
31 #include <netdb.h>
32 #endif
33 #ifdef HAVE_ARPA_INET_H
34 #include <arpa/inet.h>
35 #endif
36 #ifdef HAVE_NET_IF_H
37 #include <net/if.h>
38 #endif
39 #ifdef HAVE_SYS_IOCTL_H
40 #include <sys/ioctl.h>
41 #endif
42 
43 #ifdef HAVE_SYS_PARAM_H
44 #include <sys/param.h>
45 #endif
46 
47 #include "urldata.h"
48 #include <curl/curl.h>
49 #include "transfer.h"
50 #include "sendf.h"
51 #include "telnet.h"
52 #include "connect.h"
53 #include "progress.h"
54 #include "curl_printf.h"
55 
56 #define  TELOPTS
57 #define  TELCMDS
58 
59 #include "arpa_telnet.h"
60 #include "select.h"
61 #include "strequal.h"
62 #include "rawstr.h"
63 #include "warnless.h"
64 
65 /* The last #include files should be: */
66 #include "curl_memory.h"
67 #include "memdebug.h"
68 
69 #define SUBBUFSIZE 512
70 
71 #define CURL_SB_CLEAR(x)  x->subpointer = x->subbuffer
72 #define CURL_SB_TERM(x)                                 \
73   do {                                                  \
74     x->subend = x->subpointer;                          \
75     CURL_SB_CLEAR(x);                                   \
76   } WHILE_FALSE
77 #define CURL_SB_ACCUM(x,c)                                   \
78   do {                                                       \
79     if(x->subpointer < (x->subbuffer+sizeof x->subbuffer))   \
80       *x->subpointer++ = (c);                                \
81   } WHILE_FALSE
82 
83 #define  CURL_SB_GET(x) ((*x->subpointer++)&0xff)
84 #define  CURL_SB_PEEK(x)   ((*x->subpointer)&0xff)
85 #define  CURL_SB_EOF(x) (x->subpointer >= x->subend)
86 #define  CURL_SB_LEN(x) (x->subend - x->subpointer)
87 
88 #ifdef CURL_DISABLE_VERBOSE_STRINGS
89 #define printoption(a,b,c,d)  Curl_nop_stmt
90 #endif
91 
92 #ifdef USE_WINSOCK
93 typedef FARPROC WSOCK2_FUNC;
94 static CURLcode check_wsock2 ( struct SessionHandle *data );
95 #endif
96 
97 static
98 CURLcode telrcv(struct connectdata *,
99                 const unsigned char *inbuf, /* Data received from socket */
100                 ssize_t count);             /* Number of bytes received */
101 
102 #ifndef CURL_DISABLE_VERBOSE_STRINGS
103 static void printoption(struct SessionHandle *data,
104                         const char *direction,
105                         int cmd, int option);
106 #endif
107 
108 static void negotiate(struct connectdata *);
109 static void send_negotiation(struct connectdata *, int cmd, int option);
110 static void set_local_option(struct connectdata *, int cmd, int option);
111 static void set_remote_option(struct connectdata *, int cmd, int option);
112 
113 static void printsub(struct SessionHandle *data,
114                      int direction, unsigned char *pointer,
115                      size_t length);
116 static void suboption(struct connectdata *);
117 static void sendsuboption(struct connectdata *conn, int option);
118 
119 static CURLcode telnet_do(struct connectdata *conn, bool *done);
120 static CURLcode telnet_done(struct connectdata *conn,
121                                  CURLcode, bool premature);
122 static CURLcode send_telnet_data(struct connectdata *conn,
123                                  char *buffer, ssize_t nread);
124 
125 /* For negotiation compliant to RFC 1143 */
126 #define CURL_NO          0
127 #define CURL_YES         1
128 #define CURL_WANTYES     2
129 #define CURL_WANTNO      3
130 
131 #define CURL_EMPTY       0
132 #define CURL_OPPOSITE    1
133 
134 /*
135  * Telnet receiver states for fsm
136  */
137 typedef enum
138 {
139    CURL_TS_DATA = 0,
140    CURL_TS_IAC,
141    CURL_TS_WILL,
142    CURL_TS_WONT,
143    CURL_TS_DO,
144    CURL_TS_DONT,
145    CURL_TS_CR,
146    CURL_TS_SB,   /* sub-option collection */
147    CURL_TS_SE   /* looking for sub-option end */
148 } TelnetReceive;
149 
150 struct TELNET {
151   int please_negotiate;
152   int already_negotiated;
153   int us[256];
154   int usq[256];
155   int us_preferred[256];
156   int him[256];
157   int himq[256];
158   int him_preferred[256];
159   int subnegotiation[256];
160   char subopt_ttype[32];             /* Set with suboption TTYPE */
161   char subopt_xdisploc[128];         /* Set with suboption XDISPLOC */
162   unsigned short subopt_wsx;         /* Set with suboption NAWS */
163   unsigned short subopt_wsy;         /* Set with suboption NAWS */
164   struct curl_slist *telnet_vars;    /* Environment variables */
165 
166   /* suboptions */
167   unsigned char subbuffer[SUBBUFSIZE];
168   unsigned char *subpointer, *subend;      /* buffer for sub-options */
169 
170   TelnetReceive telrcv_state;
171 };
172 
173 
174 /*
175  * TELNET protocol handler.
176  */
177 
178 const struct Curl_handler Curl_handler_telnet = {
179   "TELNET",                             /* scheme */
180   ZERO_NULL,                            /* setup_connection */
181   telnet_do,                            /* do_it */
182   telnet_done,                          /* done */
183   ZERO_NULL,                            /* do_more */
184   ZERO_NULL,                            /* connect_it */
185   ZERO_NULL,                            /* connecting */
186   ZERO_NULL,                            /* doing */
187   ZERO_NULL,                            /* proto_getsock */
188   ZERO_NULL,                            /* doing_getsock */
189   ZERO_NULL,                            /* domore_getsock */
190   ZERO_NULL,                            /* perform_getsock */
191   ZERO_NULL,                            /* disconnect */
192   ZERO_NULL,                            /* readwrite */
193   PORT_TELNET,                          /* defport */
194   CURLPROTO_TELNET,                     /* protocol */
195   PROTOPT_NONE | PROTOPT_NOURLQUERY     /* flags */
196 };
197 
198 
199 #ifdef USE_WINSOCK
200 static CURLcode
check_wsock2(struct SessionHandle * data)201 check_wsock2 ( struct SessionHandle *data )
202 {
203   int err;
204   WORD wVersionRequested;
205   WSADATA wsaData;
206 
207   DEBUGASSERT(data);
208 
209   /* telnet requires at least WinSock 2.0 so ask for it. */
210   wVersionRequested = MAKEWORD(2, 0);
211 
212   err = WSAStartup(wVersionRequested, &wsaData);
213 
214   /* We must've called this once already, so this call */
215   /* should always succeed.  But, just in case... */
216   if(err != 0) {
217     failf(data,"WSAStartup failed (%d)",err);
218     return CURLE_FAILED_INIT;
219   }
220 
221   /* We have to have a WSACleanup call for every successful */
222   /* WSAStartup call. */
223   WSACleanup();
224 
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 "
230           "telnet");
231     return CURLE_FAILED_INIT;
232   }
233 
234   /* Our version is supported */
235   return CURLE_OK;
236 }
237 #endif
238 
239 static
init_telnet(struct connectdata * conn)240 CURLcode init_telnet(struct connectdata *conn)
241 {
242   struct TELNET *tn;
243 
244   tn = calloc(1, sizeof(struct TELNET));
245   if(!tn)
246     return CURLE_OUT_OF_MEMORY;
247 
248   conn->data->req.protop = tn; /* make us known */
249 
250   tn->telrcv_state = CURL_TS_DATA;
251 
252   /* Init suboptions */
253   CURL_SB_CLEAR(tn);
254 
255   /* Set the options we want by default */
256   tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES;
257   tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES;
258 
259   /* To be compliant with previous releases of libcurl
260      we enable this option by default. This behaviour
261          can be changed thanks to the "BINARY" option in
262          CURLOPT_TELNETOPTIONS
263   */
264   tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES;
265   tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES;
266 
267   /* We must allow the server to echo what we sent
268          but it is not necessary to request the server
269          to do so (it might forces the server to close
270          the connection). Hence, we ignore ECHO in the
271          negotiate function
272   */
273   tn->him_preferred[CURL_TELOPT_ECHO] = CURL_YES;
274 
275   /* Set the subnegotiation fields to send information
276     just after negotiation passed (do/will)
277 
278      Default values are (0,0) initialized by calloc.
279      According to the RFC1013 it is valid:
280      A value equal to zero is acceptable for the width (or height),
281          and means that no character width (or height) is being sent.
282          In this case, the width (or height) that will be assumed by the
283          Telnet server is operating system specific (it will probably be
284          based upon the terminal type information that may have been sent
285          using the TERMINAL TYPE Telnet option). */
286   tn->subnegotiation[CURL_TELOPT_NAWS] = CURL_YES;
287   return CURLE_OK;
288 }
289 
negotiate(struct connectdata * conn)290 static void negotiate(struct connectdata *conn)
291 {
292   int i;
293   struct TELNET *tn = (struct TELNET *) conn->data->req.protop;
294 
295   for(i = 0;i < CURL_NTELOPTS;i++) {
296     if(i==CURL_TELOPT_ECHO)
297       continue;
298 
299     if(tn->us_preferred[i] == CURL_YES)
300       set_local_option(conn, i, CURL_YES);
301 
302     if(tn->him_preferred[i] == CURL_YES)
303       set_remote_option(conn, i, CURL_YES);
304   }
305 }
306 
307 #ifndef CURL_DISABLE_VERBOSE_STRINGS
printoption(struct SessionHandle * data,const char * direction,int cmd,int option)308 static void printoption(struct SessionHandle *data,
309                         const char *direction, int cmd, int option)
310 {
311   const char *fmt;
312   const char *opt;
313 
314   if(data->set.verbose) {
315     if(cmd == CURL_IAC) {
316       if(CURL_TELCMD_OK(option))
317         infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option));
318       else
319         infof(data, "%s IAC %d\n", direction, option);
320     }
321     else {
322       fmt = (cmd == CURL_WILL) ? "WILL" : (cmd == CURL_WONT) ? "WONT" :
323         (cmd == CURL_DO) ? "DO" : (cmd == CURL_DONT) ? "DONT" : 0;
324       if(fmt) {
325         if(CURL_TELOPT_OK(option))
326           opt = CURL_TELOPT(option);
327         else if(option == CURL_TELOPT_EXOPL)
328           opt = "EXOPL";
329         else
330           opt = NULL;
331 
332         if(opt)
333           infof(data, "%s %s %s\n", direction, fmt, opt);
334         else
335           infof(data, "%s %s %d\n", direction, fmt, option);
336       }
337       else
338         infof(data, "%s %d %d\n", direction, cmd, option);
339     }
340   }
341 }
342 #endif
343 
send_negotiation(struct connectdata * conn,int cmd,int option)344 static void send_negotiation(struct connectdata *conn, int cmd, int option)
345 {
346    unsigned char buf[3];
347    ssize_t bytes_written;
348    int err;
349    struct SessionHandle *data = conn->data;
350 
351    buf[0] = CURL_IAC;
352    buf[1] = (unsigned char)cmd;
353    buf[2] = (unsigned char)option;
354 
355    bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3);
356    if(bytes_written < 0) {
357      err = SOCKERRNO;
358      failf(data,"Sending data failed (%d)",err);
359    }
360 
361    printoption(conn->data, "SENT", cmd, option);
362 }
363 
364 static
set_remote_option(struct connectdata * conn,int option,int newstate)365 void set_remote_option(struct connectdata *conn, int option, int newstate)
366 {
367   struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
368   if(newstate == CURL_YES) {
369     switch(tn->him[option]) {
370     case CURL_NO:
371       tn->him[option] = CURL_WANTYES;
372       send_negotiation(conn, CURL_DO, option);
373       break;
374 
375     case CURL_YES:
376       /* Already enabled */
377       break;
378 
379     case CURL_WANTNO:
380       switch(tn->himq[option]) {
381       case CURL_EMPTY:
382         /* Already negotiating for CURL_YES, queue the request */
383         tn->himq[option] = CURL_OPPOSITE;
384         break;
385       case CURL_OPPOSITE:
386         /* Error: already queued an enable request */
387         break;
388       }
389       break;
390 
391     case CURL_WANTYES:
392       switch(tn->himq[option]) {
393       case CURL_EMPTY:
394         /* Error: already negotiating for enable */
395         break;
396       case CURL_OPPOSITE:
397         tn->himq[option] = CURL_EMPTY;
398         break;
399       }
400       break;
401     }
402   }
403   else { /* NO */
404     switch(tn->him[option]) {
405     case CURL_NO:
406       /* Already disabled */
407       break;
408 
409     case CURL_YES:
410       tn->him[option] = CURL_WANTNO;
411       send_negotiation(conn, CURL_DONT, option);
412       break;
413 
414     case CURL_WANTNO:
415       switch(tn->himq[option]) {
416       case CURL_EMPTY:
417         /* Already negotiating for NO */
418         break;
419       case CURL_OPPOSITE:
420         tn->himq[option] = CURL_EMPTY;
421         break;
422       }
423       break;
424 
425     case CURL_WANTYES:
426       switch(tn->himq[option]) {
427       case CURL_EMPTY:
428         tn->himq[option] = CURL_OPPOSITE;
429         break;
430       case CURL_OPPOSITE:
431         break;
432       }
433       break;
434     }
435   }
436 }
437 
438 static
rec_will(struct connectdata * conn,int option)439 void rec_will(struct connectdata *conn, int option)
440 {
441   struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
442   switch(tn->him[option]) {
443   case CURL_NO:
444     if(tn->him_preferred[option] == CURL_YES) {
445       tn->him[option] = CURL_YES;
446       send_negotiation(conn, CURL_DO, option);
447     }
448     else
449       send_negotiation(conn, CURL_DONT, option);
450 
451     break;
452 
453   case CURL_YES:
454     /* Already enabled */
455     break;
456 
457   case CURL_WANTNO:
458     switch(tn->himq[option]) {
459     case CURL_EMPTY:
460       /* Error: DONT answered by WILL */
461       tn->him[option] = CURL_NO;
462       break;
463     case CURL_OPPOSITE:
464       /* Error: DONT answered by WILL */
465       tn->him[option] = CURL_YES;
466       tn->himq[option] = CURL_EMPTY;
467       break;
468     }
469     break;
470 
471   case CURL_WANTYES:
472     switch(tn->himq[option]) {
473     case CURL_EMPTY:
474       tn->him[option] = CURL_YES;
475       break;
476     case CURL_OPPOSITE:
477       tn->him[option] = CURL_WANTNO;
478       tn->himq[option] = CURL_EMPTY;
479       send_negotiation(conn, CURL_DONT, option);
480       break;
481     }
482     break;
483   }
484 }
485 
486 static
rec_wont(struct connectdata * conn,int option)487 void rec_wont(struct connectdata *conn, int option)
488 {
489   struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
490   switch(tn->him[option]) {
491   case CURL_NO:
492     /* Already disabled */
493     break;
494 
495   case CURL_YES:
496     tn->him[option] = CURL_NO;
497     send_negotiation(conn, CURL_DONT, option);
498     break;
499 
500   case CURL_WANTNO:
501     switch(tn->himq[option]) {
502     case CURL_EMPTY:
503       tn->him[option] = CURL_NO;
504       break;
505 
506     case CURL_OPPOSITE:
507       tn->him[option] = CURL_WANTYES;
508       tn->himq[option] = CURL_EMPTY;
509       send_negotiation(conn, CURL_DO, option);
510       break;
511     }
512     break;
513 
514   case CURL_WANTYES:
515     switch(tn->himq[option]) {
516     case CURL_EMPTY:
517       tn->him[option] = CURL_NO;
518       break;
519     case CURL_OPPOSITE:
520       tn->him[option] = CURL_NO;
521       tn->himq[option] = CURL_EMPTY;
522       break;
523     }
524     break;
525   }
526 }
527 
528 static void
set_local_option(struct connectdata * conn,int option,int newstate)529 set_local_option(struct connectdata *conn, int option, int newstate)
530 {
531   struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
532   if(newstate == CURL_YES) {
533     switch(tn->us[option]) {
534     case CURL_NO:
535       tn->us[option] = CURL_WANTYES;
536       send_negotiation(conn, CURL_WILL, option);
537       break;
538 
539     case CURL_YES:
540       /* Already enabled */
541       break;
542 
543     case CURL_WANTNO:
544       switch(tn->usq[option]) {
545       case CURL_EMPTY:
546         /* Already negotiating for CURL_YES, queue the request */
547         tn->usq[option] = CURL_OPPOSITE;
548         break;
549       case CURL_OPPOSITE:
550         /* Error: already queued an enable request */
551         break;
552       }
553       break;
554 
555     case CURL_WANTYES:
556       switch(tn->usq[option]) {
557       case CURL_EMPTY:
558         /* Error: already negotiating for enable */
559         break;
560       case CURL_OPPOSITE:
561         tn->usq[option] = CURL_EMPTY;
562         break;
563       }
564       break;
565     }
566   }
567   else { /* NO */
568     switch(tn->us[option]) {
569     case CURL_NO:
570       /* Already disabled */
571       break;
572 
573     case CURL_YES:
574       tn->us[option] = CURL_WANTNO;
575       send_negotiation(conn, CURL_WONT, option);
576       break;
577 
578     case CURL_WANTNO:
579       switch(tn->usq[option]) {
580       case CURL_EMPTY:
581         /* Already negotiating for NO */
582         break;
583       case CURL_OPPOSITE:
584         tn->usq[option] = CURL_EMPTY;
585         break;
586       }
587       break;
588 
589     case CURL_WANTYES:
590       switch(tn->usq[option]) {
591       case CURL_EMPTY:
592         tn->usq[option] = CURL_OPPOSITE;
593         break;
594       case CURL_OPPOSITE:
595         break;
596       }
597       break;
598     }
599   }
600 }
601 
602 static
rec_do(struct connectdata * conn,int option)603 void rec_do(struct connectdata *conn, int option)
604 {
605   struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
606   switch(tn->us[option]) {
607   case CURL_NO:
608     if(tn->us_preferred[option] == CURL_YES) {
609       tn->us[option] = CURL_YES;
610       send_negotiation(conn, CURL_WILL, option);
611       if(tn->subnegotiation[option] == CURL_YES)
612         /* transmission of data option */
613         sendsuboption(conn, option);
614     }
615     else if(tn->subnegotiation[option] == CURL_YES) {
616       /* send information to achieve this option*/
617       tn->us[option] = CURL_YES;
618       send_negotiation(conn, CURL_WILL, option);
619       sendsuboption(conn, option);
620     }
621     else
622       send_negotiation(conn, CURL_WONT, option);
623     break;
624 
625   case CURL_YES:
626     /* Already enabled */
627     break;
628 
629   case CURL_WANTNO:
630     switch(tn->usq[option]) {
631     case CURL_EMPTY:
632       /* Error: DONT answered by WILL */
633       tn->us[option] = CURL_NO;
634       break;
635     case CURL_OPPOSITE:
636       /* Error: DONT answered by WILL */
637       tn->us[option] = CURL_YES;
638       tn->usq[option] = CURL_EMPTY;
639       break;
640     }
641     break;
642 
643   case CURL_WANTYES:
644     switch(tn->usq[option]) {
645     case CURL_EMPTY:
646       tn->us[option] = CURL_YES;
647       if(tn->subnegotiation[option] == CURL_YES) {
648         /* transmission of data option */
649         sendsuboption(conn, option);
650       }
651       break;
652     case CURL_OPPOSITE:
653       tn->us[option] = CURL_WANTNO;
654       tn->himq[option] = CURL_EMPTY;
655       send_negotiation(conn, CURL_WONT, option);
656       break;
657     }
658     break;
659   }
660 }
661 
662 static
rec_dont(struct connectdata * conn,int option)663 void rec_dont(struct connectdata *conn, int option)
664 {
665   struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
666   switch(tn->us[option]) {
667   case CURL_NO:
668     /* Already disabled */
669     break;
670 
671   case CURL_YES:
672     tn->us[option] = CURL_NO;
673     send_negotiation(conn, CURL_WONT, option);
674     break;
675 
676   case CURL_WANTNO:
677     switch(tn->usq[option]) {
678     case CURL_EMPTY:
679       tn->us[option] = CURL_NO;
680       break;
681 
682     case CURL_OPPOSITE:
683       tn->us[option] = CURL_WANTYES;
684       tn->usq[option] = CURL_EMPTY;
685       send_negotiation(conn, CURL_WILL, option);
686       break;
687     }
688     break;
689 
690   case CURL_WANTYES:
691     switch(tn->usq[option]) {
692     case CURL_EMPTY:
693       tn->us[option] = CURL_NO;
694       break;
695     case CURL_OPPOSITE:
696       tn->us[option] = CURL_NO;
697       tn->usq[option] = CURL_EMPTY;
698       break;
699     }
700     break;
701   }
702 }
703 
704 
printsub(struct SessionHandle * data,int direction,unsigned char * pointer,size_t length)705 static void printsub(struct SessionHandle *data,
706                      int direction,             /* '<' or '>' */
707                      unsigned char *pointer,    /* where suboption data is */
708                      size_t length)             /* length of suboption data */
709 {
710   unsigned int i = 0;
711 
712   if(data->set.verbose) {
713     if(direction) {
714       infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
715       if(length >= 3) {
716         int j;
717 
718         i = pointer[length-2];
719         j = pointer[length-1];
720 
721         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));
727           else
728             infof(data, "%u ", 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));
733           else
734             infof(data, "%d", j);
735           infof(data, ", not IAC SE!) ");
736         }
737       }
738       length -= 2;
739     }
740     if(length < 1) {
741       infof(data, "(Empty suboption?)");
742       return;
743     }
744 
745     if(CURL_TELOPT_OK(pointer[0])) {
746       switch(pointer[0]) {
747       case CURL_TELOPT_TTYPE:
748       case CURL_TELOPT_XDISPLOC:
749       case CURL_TELOPT_NEW_ENVIRON:
750       case CURL_TELOPT_NAWS:
751         infof(data, "%s", CURL_TELOPT(pointer[0]));
752         break;
753       default:
754         infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
755         break;
756       }
757     }
758     else
759       infof(data, "%d (unknown)", pointer[i]);
760 
761     switch(pointer[0]) {
762     case CURL_TELOPT_NAWS:
763       if(length > 4)
764         infof(data, "Width: %hu ; Height: %hu", (pointer[1]<<8) | pointer[2],
765               (pointer[3]<<8) | pointer[4]);
766       break;
767     default:
768       switch(pointer[1]) {
769       case CURL_TELQUAL_IS:
770         infof(data, " IS");
771         break;
772       case CURL_TELQUAL_SEND:
773         infof(data, " SEND");
774         break;
775       case CURL_TELQUAL_INFO:
776         infof(data, " INFO/REPLY");
777         break;
778       case CURL_TELQUAL_NAME:
779         infof(data, " NAME");
780         break;
781       }
782 
783       switch(pointer[0]) {
784       case CURL_TELOPT_TTYPE:
785       case CURL_TELOPT_XDISPLOC:
786         pointer[length] = 0;
787         infof(data, " \"%s\"", &pointer[2]);
788         break;
789       case CURL_TELOPT_NEW_ENVIRON:
790         if(pointer[1] == CURL_TELQUAL_IS) {
791           infof(data, " ");
792           for(i = 3;i < length;i++) {
793             switch(pointer[i]) {
794             case CURL_NEW_ENV_VAR:
795               infof(data, ", ");
796               break;
797             case CURL_NEW_ENV_VALUE:
798               infof(data, " = ");
799               break;
800             default:
801               infof(data, "%c", pointer[i]);
802               break;
803             }
804           }
805         }
806         break;
807       default:
808         for(i = 2; i < length; i++)
809           infof(data, " %.2x", pointer[i]);
810         break;
811       }
812     }
813     if(direction)
814       infof(data, "\n");
815   }
816 }
817 
check_telnet_options(struct connectdata * conn)818 static CURLcode check_telnet_options(struct connectdata *conn)
819 {
820   struct curl_slist *head;
821   struct curl_slist *beg;
822   char option_keyword[128] = "";
823   char option_arg[256] = "";
824   struct SessionHandle *data = conn->data;
825   struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
826   CURLcode result = CURLE_OK;
827   int binary_option;
828 
829   /* Add the user name as an environment variable if it
830      was given on the command line */
831   if(conn->bits.user_passwd) {
832     snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
833     beg = curl_slist_append(tn->telnet_vars, option_arg);
834     if(!beg) {
835       curl_slist_free_all(tn->telnet_vars);
836       tn->telnet_vars = NULL;
837       return CURLE_OUT_OF_MEMORY;
838     }
839     tn->telnet_vars = beg;
840     tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
841   }
842 
843   for(head = data->set.telnet_options; head; head=head->next) {
844     if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
845               option_keyword, option_arg) == 2) {
846 
847       /* Terminal type */
848       if(Curl_raw_equal(option_keyword, "TTYPE")) {
849         strncpy(tn->subopt_ttype, option_arg, 31);
850         tn->subopt_ttype[31] = 0; /* String termination */
851         tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
852         continue;
853       }
854 
855       /* Display variable */
856       if(Curl_raw_equal(option_keyword, "XDISPLOC")) {
857         strncpy(tn->subopt_xdisploc, option_arg, 127);
858         tn->subopt_xdisploc[127] = 0; /* String termination */
859         tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
860         continue;
861       }
862 
863       /* Environment variable */
864       if(Curl_raw_equal(option_keyword, "NEW_ENV")) {
865         beg = curl_slist_append(tn->telnet_vars, option_arg);
866         if(!beg) {
867           result = CURLE_OUT_OF_MEMORY;
868           break;
869         }
870         tn->telnet_vars = beg;
871         tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
872         continue;
873       }
874 
875           /* Window Size */
876       if(Curl_raw_equal(option_keyword, "WS")) {
877         if(sscanf(option_arg, "%hu%*[xX]%hu",
878                   &tn->subopt_wsx, &tn->subopt_wsy) == 2)
879           tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
880         else {
881           failf(data, "Syntax error in telnet option: %s", head->data);
882           result = CURLE_TELNET_OPTION_SYNTAX;
883           break;
884         }
885         continue;
886       }
887 
888       /* To take care or not of the 8th bit in data exchange */
889       if(Curl_raw_equal(option_keyword, "BINARY")) {
890         binary_option=atoi(option_arg);
891         if(binary_option!=1) {
892           tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO;
893           tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO;
894         }
895         continue;
896       }
897 
898       failf(data, "Unknown telnet option %s", head->data);
899       result = CURLE_UNKNOWN_TELNET_OPTION;
900       break;
901     }
902     else {
903       failf(data, "Syntax error in telnet option: %s", head->data);
904       result = CURLE_TELNET_OPTION_SYNTAX;
905       break;
906     }
907   }
908 
909   if(result) {
910     curl_slist_free_all(tn->telnet_vars);
911     tn->telnet_vars = NULL;
912   }
913 
914   return result;
915 }
916 
917 /*
918  * suboption()
919  *
920  * Look at the sub-option buffer, and try to be helpful to the other
921  * side.
922  */
923 
suboption(struct connectdata * conn)924 static void suboption(struct connectdata *conn)
925 {
926   struct curl_slist *v;
927   unsigned char temp[2048];
928   ssize_t bytes_written;
929   size_t len;
930   size_t tmplen;
931   int err;
932   char varname[128] = "";
933   char varval[128] = "";
934   struct SessionHandle *data = conn->data;
935   struct TELNET *tn = (struct TELNET *)data->req.protop;
936 
937   printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn)+2);
938   switch (CURL_SB_GET(tn)) {
939     case CURL_TELOPT_TTYPE:
940       len = strlen(tn->subopt_ttype) + 4 + 2;
941       snprintf((char *)temp, sizeof(temp),
942                "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
943                CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE);
944       bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
945       if(bytes_written < 0) {
946         err = SOCKERRNO;
947         failf(data,"Sending data failed (%d)",err);
948       }
949       printsub(data, '>', &temp[2], len-2);
950       break;
951     case CURL_TELOPT_XDISPLOC:
952       len = strlen(tn->subopt_xdisploc) + 4 + 2;
953       snprintf((char *)temp, sizeof(temp),
954                "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
955                CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE);
956       bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
957       if(bytes_written < 0) {
958         err = SOCKERRNO;
959         failf(data,"Sending data failed (%d)",err);
960       }
961       printsub(data, '>', &temp[2], len-2);
962       break;
963     case CURL_TELOPT_NEW_ENVIRON:
964       snprintf((char *)temp, sizeof(temp),
965                "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON,
966                CURL_TELQUAL_IS);
967       len = 4;
968 
969       for(v = tn->telnet_vars;v;v = v->next) {
970         tmplen = (strlen(v->data) + 1);
971         /* Add the variable only if it fits */
972         if(len + tmplen < (int)sizeof(temp)-6) {
973           if(sscanf(v->data, "%127[^,],%127s", varname, varval)) {
974             snprintf((char *)&temp[len], sizeof(temp) - len,
975                      "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
976                      CURL_NEW_ENV_VALUE, varval);
977             len += tmplen;
978           }
979         }
980       }
981       snprintf((char *)&temp[len], sizeof(temp) - len,
982                "%c%c", CURL_IAC, CURL_SE);
983       len += 2;
984       bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
985       if(bytes_written < 0) {
986         err = SOCKERRNO;
987         failf(data,"Sending data failed (%d)",err);
988       }
989       printsub(data, '>', &temp[2], len-2);
990       break;
991   }
992   return;
993 }
994 
995 
996 /*
997  * sendsuboption()
998  *
999  * Send suboption information to the server side.
1000  */
1001 
sendsuboption(struct connectdata * conn,int option)1002 static void sendsuboption(struct connectdata *conn, int option)
1003 {
1004   ssize_t bytes_written;
1005   int err;
1006   unsigned short x, y;
1007   unsigned char*uc1, *uc2;
1008 
1009   struct SessionHandle *data = conn->data;
1010   struct TELNET *tn = (struct TELNET *)data->req.protop;
1011 
1012   switch (option) {
1013   case CURL_TELOPT_NAWS:
1014     /* We prepare data to be sent */
1015     CURL_SB_CLEAR(tn);
1016     CURL_SB_ACCUM(tn, CURL_IAC);
1017     CURL_SB_ACCUM(tn, CURL_SB);
1018     CURL_SB_ACCUM(tn, CURL_TELOPT_NAWS);
1019     /* We must deal either with litte or big endien processors */
1020     /* Window size must be sent according to the 'network order' */
1021     x=htons(tn->subopt_wsx);
1022     y=htons(tn->subopt_wsy);
1023     uc1 = (unsigned char*)&x;
1024     uc2 = (unsigned char*)&y;
1025     CURL_SB_ACCUM(tn, uc1[0]);
1026     CURL_SB_ACCUM(tn, uc1[1]);
1027     CURL_SB_ACCUM(tn, uc2[0]);
1028     CURL_SB_ACCUM(tn, uc2[1]);
1029 
1030     CURL_SB_ACCUM(tn, CURL_IAC);
1031     CURL_SB_ACCUM(tn, CURL_SE);
1032     CURL_SB_TERM(tn);
1033     /* data suboption is now ready */
1034 
1035     printsub(data, '>', (unsigned char *)tn->subbuffer+2,
1036              CURL_SB_LEN(tn)-2);
1037 
1038     /* we send the header of the suboption... */
1039     bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer, 3);
1040     if(bytes_written < 0) {
1041       err = SOCKERRNO;
1042       failf(data, "Sending data failed (%d)", err);
1043     }
1044     /* ... then the window size with the send_telnet_data() function
1045        to deal with 0xFF cases ... */
1046     send_telnet_data(conn, (char *)tn->subbuffer+3, 4);
1047     /* ... and the footer */
1048     bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer+7, 2);
1049     if(bytes_written < 0) {
1050       err = SOCKERRNO;
1051       failf(data, "Sending data failed (%d)", err);
1052     }
1053     break;
1054   }
1055 }
1056 
1057 
1058 static
telrcv(struct connectdata * conn,const unsigned char * inbuf,ssize_t count)1059 CURLcode telrcv(struct connectdata *conn,
1060                 const unsigned char *inbuf, /* Data received from socket */
1061                 ssize_t count)              /* Number of bytes received */
1062 {
1063   unsigned char c;
1064   CURLcode result;
1065   int in = 0;
1066   int startwrite=-1;
1067   struct SessionHandle *data = conn->data;
1068   struct TELNET *tn = (struct TELNET *)data->req.protop;
1069 
1070 #define startskipping()                                       \
1071   if(startwrite >= 0) {                                       \
1072     result = Curl_client_write(conn,                          \
1073                                CLIENTWRITE_BODY,              \
1074                                (char *)&inbuf[startwrite],    \
1075                                in-startwrite);                \
1076     if(result)                                                \
1077       return result;                                          \
1078   }                                                           \
1079   startwrite = -1
1080 
1081 #define writebyte() \
1082     if(startwrite < 0) \
1083       startwrite = in
1084 
1085 #define bufferflush() startskipping()
1086 
1087   while(count--) {
1088     c = inbuf[in];
1089 
1090     switch (tn->telrcv_state) {
1091     case CURL_TS_CR:
1092       tn->telrcv_state = CURL_TS_DATA;
1093       if(c == '\0') {
1094         startskipping();
1095         break;   /* Ignore \0 after CR */
1096       }
1097       writebyte();
1098       break;
1099 
1100     case CURL_TS_DATA:
1101       if(c == CURL_IAC) {
1102         tn->telrcv_state = CURL_TS_IAC;
1103         startskipping();
1104         break;
1105       }
1106       else if(c == '\r')
1107         tn->telrcv_state = CURL_TS_CR;
1108       writebyte();
1109       break;
1110 
1111     case CURL_TS_IAC:
1112     process_iac:
1113       DEBUGASSERT(startwrite < 0);
1114       switch (c) {
1115       case CURL_WILL:
1116         tn->telrcv_state = CURL_TS_WILL;
1117         break;
1118       case CURL_WONT:
1119         tn->telrcv_state = CURL_TS_WONT;
1120         break;
1121       case CURL_DO:
1122         tn->telrcv_state = CURL_TS_DO;
1123         break;
1124       case CURL_DONT:
1125         tn->telrcv_state = CURL_TS_DONT;
1126         break;
1127       case CURL_SB:
1128         CURL_SB_CLEAR(tn);
1129         tn->telrcv_state = CURL_TS_SB;
1130         break;
1131       case CURL_IAC:
1132         tn->telrcv_state = CURL_TS_DATA;
1133         writebyte();
1134         break;
1135       case CURL_DM:
1136       case CURL_NOP:
1137       case CURL_GA:
1138       default:
1139         tn->telrcv_state = CURL_TS_DATA;
1140         printoption(data, "RCVD", CURL_IAC, c);
1141         break;
1142       }
1143       break;
1144 
1145       case CURL_TS_WILL:
1146         printoption(data, "RCVD", CURL_WILL, c);
1147         tn->please_negotiate = 1;
1148         rec_will(conn, c);
1149         tn->telrcv_state = CURL_TS_DATA;
1150         break;
1151 
1152       case CURL_TS_WONT:
1153         printoption(data, "RCVD", CURL_WONT, c);
1154         tn->please_negotiate = 1;
1155         rec_wont(conn, c);
1156         tn->telrcv_state = CURL_TS_DATA;
1157         break;
1158 
1159       case CURL_TS_DO:
1160         printoption(data, "RCVD", CURL_DO, c);
1161         tn->please_negotiate = 1;
1162         rec_do(conn, c);
1163         tn->telrcv_state = CURL_TS_DATA;
1164         break;
1165 
1166       case CURL_TS_DONT:
1167         printoption(data, "RCVD", CURL_DONT, c);
1168         tn->please_negotiate = 1;
1169         rec_dont(conn, c);
1170         tn->telrcv_state = CURL_TS_DATA;
1171         break;
1172 
1173       case CURL_TS_SB:
1174         if(c == CURL_IAC)
1175           tn->telrcv_state = CURL_TS_SE;
1176         else
1177           CURL_SB_ACCUM(tn, c);
1178         break;
1179 
1180       case CURL_TS_SE:
1181         if(c != CURL_SE) {
1182           if(c != CURL_IAC) {
1183             /*
1184              * This is an error.  We only expect to get "IAC IAC" or "IAC SE".
1185              * Several things may have happened.  An IAC was not doubled, the
1186              * IAC SE was left off, or another option got inserted into the
1187              * suboption are all possibilities.  If we assume that the IAC was
1188              * not doubled, and really the IAC SE was left off, we could get
1189              * into an infinate loop here.  So, instead, we terminate the
1190              * suboption, and process the partial suboption if we can.
1191              */
1192             CURL_SB_ACCUM(tn, CURL_IAC);
1193             CURL_SB_ACCUM(tn, c);
1194             tn->subpointer -= 2;
1195             CURL_SB_TERM(tn);
1196 
1197             printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c);
1198             suboption(conn);   /* handle sub-option */
1199             tn->telrcv_state = CURL_TS_IAC;
1200             goto process_iac;
1201           }
1202           CURL_SB_ACCUM(tn, c);
1203           tn->telrcv_state = CURL_TS_SB;
1204         }
1205         else
1206         {
1207           CURL_SB_ACCUM(tn, CURL_IAC);
1208           CURL_SB_ACCUM(tn, CURL_SE);
1209           tn->subpointer -= 2;
1210           CURL_SB_TERM(tn);
1211           suboption(conn);   /* handle sub-option */
1212           tn->telrcv_state = CURL_TS_DATA;
1213         }
1214         break;
1215     }
1216     ++in;
1217   }
1218   bufferflush();
1219   return CURLE_OK;
1220 }
1221 
1222 /* Escape and send a telnet data block */
1223 /* TODO: write large chunks of data instead of one byte at a time */
send_telnet_data(struct connectdata * conn,char * buffer,ssize_t nread)1224 static CURLcode send_telnet_data(struct connectdata *conn,
1225                                  char *buffer, ssize_t nread)
1226 {
1227   unsigned char outbuf[2];
1228   ssize_t bytes_written, total_written;
1229   int out_count;
1230   CURLcode result = CURLE_OK;
1231 
1232   while(!result && nread--) {
1233     outbuf[0] = *buffer++;
1234     out_count = 1;
1235     if(outbuf[0] == CURL_IAC)
1236       outbuf[out_count++] = CURL_IAC;
1237 
1238     total_written = 0;
1239     do {
1240       /* Make sure socket is writable to avoid EWOULDBLOCK condition */
1241       struct pollfd pfd[1];
1242       pfd[0].fd = conn->sock[FIRSTSOCKET];
1243       pfd[0].events = POLLOUT;
1244       switch (Curl_poll(pfd, 1, -1)) {
1245         case -1:                    /* error, abort writing */
1246         case 0:                     /* timeout (will never happen) */
1247           result = CURLE_SEND_ERROR;
1248           break;
1249         default:                    /* write! */
1250           bytes_written = 0;
1251           result = Curl_write(conn, conn->sock[FIRSTSOCKET],
1252                               outbuf+total_written, out_count-total_written,
1253                               &bytes_written);
1254           total_written += bytes_written;
1255           break;
1256       }
1257       /* handle partial write */
1258     } while(!result && total_written < out_count);
1259   }
1260   return result;
1261 }
1262 
telnet_done(struct connectdata * conn,CURLcode status,bool premature)1263 static CURLcode telnet_done(struct connectdata *conn,
1264                                  CURLcode status, bool premature)
1265 {
1266   struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
1267   (void)status; /* unused */
1268   (void)premature; /* not used */
1269 
1270   if(!tn)
1271     return CURLE_OK;
1272 
1273   curl_slist_free_all(tn->telnet_vars);
1274   tn->telnet_vars = NULL;
1275 
1276   Curl_safefree(conn->data->req.protop);
1277 
1278   return CURLE_OK;
1279 }
1280 
telnet_do(struct connectdata * conn,bool * done)1281 static CURLcode telnet_do(struct connectdata *conn, bool *done)
1282 {
1283   CURLcode result;
1284   struct SessionHandle *data = conn->data;
1285   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
1286 #ifdef USE_WINSOCK
1287   HMODULE wsock2;
1288   WSOCK2_FUNC close_event_func;
1289   WSOCK2_FUNC create_event_func;
1290   WSOCK2_FUNC event_select_func;
1291   WSOCK2_FUNC enum_netevents_func;
1292   WSAEVENT event_handle;
1293   WSANETWORKEVENTS events;
1294   HANDLE stdin_handle;
1295   HANDLE objs[2];
1296   DWORD  obj_count;
1297   DWORD  wait_timeout;
1298   DWORD waitret;
1299   DWORD readfile_read;
1300   int err;
1301 #else
1302   int interval_ms;
1303   struct pollfd pfd[2];
1304   int poll_cnt;
1305   curl_off_t total_dl = 0;
1306   curl_off_t total_ul = 0;
1307 #endif
1308   ssize_t nread;
1309   struct timeval now;
1310   bool keepon = TRUE;
1311   char *buf = data->state.buffer;
1312   struct TELNET *tn;
1313 
1314   *done = TRUE; /* unconditionally */
1315 
1316   result = init_telnet(conn);
1317   if(result)
1318     return result;
1319 
1320   tn = (struct TELNET *)data->req.protop;
1321 
1322   result = check_telnet_options(conn);
1323   if(result)
1324     return result;
1325 
1326 #ifdef USE_WINSOCK
1327   /*
1328   ** This functionality only works with WinSock >= 2.0.  So,
1329   ** make sure have it.
1330   */
1331   result = check_wsock2(data);
1332   if(result)
1333     return result;
1334 
1335   /* OK, so we have WinSock 2.0.  We need to dynamically */
1336   /* load ws2_32.dll and get the function pointers we need. */
1337   wsock2 = LoadLibrary(TEXT("WS2_32.DLL"));
1338   if(wsock2 == NULL) {
1339     failf(data, "failed to load WS2_32.DLL (%d)", ERRNO);
1340     return CURLE_FAILED_INIT;
1341   }
1342 
1343   /* Grab a pointer to WSACreateEvent */
1344   create_event_func = GetProcAddress(wsock2, "WSACreateEvent");
1345   if(create_event_func == NULL) {
1346     failf(data, "failed to find WSACreateEvent function (%d)", ERRNO);
1347     FreeLibrary(wsock2);
1348     return CURLE_FAILED_INIT;
1349   }
1350 
1351   /* And WSACloseEvent */
1352   close_event_func = GetProcAddress(wsock2, "WSACloseEvent");
1353   if(close_event_func == NULL) {
1354     failf(data, "failed to find WSACloseEvent function (%d)", ERRNO);
1355     FreeLibrary(wsock2);
1356     return CURLE_FAILED_INIT;
1357   }
1358 
1359   /* And WSAEventSelect */
1360   event_select_func = GetProcAddress(wsock2, "WSAEventSelect");
1361   if(event_select_func == NULL) {
1362     failf(data, "failed to find WSAEventSelect function (%d)", ERRNO);
1363     FreeLibrary(wsock2);
1364     return CURLE_FAILED_INIT;
1365   }
1366 
1367   /* And WSAEnumNetworkEvents */
1368   enum_netevents_func = GetProcAddress(wsock2, "WSAEnumNetworkEvents");
1369   if(enum_netevents_func == NULL) {
1370     failf(data, "failed to find WSAEnumNetworkEvents function (%d)", ERRNO);
1371     FreeLibrary(wsock2);
1372     return CURLE_FAILED_INIT;
1373   }
1374 
1375   /* We want to wait for both stdin and the socket. Since
1376   ** the select() function in winsock only works on sockets
1377   ** we have to use the WaitForMultipleObjects() call.
1378   */
1379 
1380   /* First, create a sockets event object */
1381   event_handle = (WSAEVENT)create_event_func();
1382   if(event_handle == WSA_INVALID_EVENT) {
1383     failf(data, "WSACreateEvent failed (%d)", SOCKERRNO);
1384     FreeLibrary(wsock2);
1385     return CURLE_FAILED_INIT;
1386   }
1387 
1388   /* Tell winsock what events we want to listen to */
1389   if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) ==
1390      SOCKET_ERROR) {
1391     close_event_func(event_handle);
1392     FreeLibrary(wsock2);
1393     return CURLE_OK;
1394   }
1395 
1396   /* The get the Windows file handle for stdin */
1397   stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
1398 
1399   /* Create the list of objects to wait for */
1400   objs[0] = event_handle;
1401   objs[1] = stdin_handle;
1402 
1403   /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
1404      else use the old WaitForMultipleObjects() way */
1405   if(GetFileType(stdin_handle) == FILE_TYPE_PIPE ||
1406      data->set.is_fread_set) {
1407     /* Don't wait for stdin_handle, just wait for event_handle */
1408     obj_count = 1;
1409     /* Check stdin_handle per 100 milliseconds */
1410     wait_timeout = 100;
1411   }
1412   else {
1413     obj_count = 2;
1414     wait_timeout = 1000;
1415   }
1416 
1417   /* Keep on listening and act on events */
1418   while(keepon) {
1419     waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout);
1420     switch(waitret) {
1421     case WAIT_TIMEOUT:
1422     {
1423       for(;;) {
1424         if(data->set.is_fread_set) {
1425           /* read from user-supplied method */
1426           result = (int)data->set.fread_func(buf, 1, BUFSIZE - 1,
1427                                              data->set.in);
1428           if(result == CURL_READFUNC_ABORT) {
1429             keepon = FALSE;
1430             result = CURLE_READ_ERROR;
1431             break;
1432           }
1433 
1434           if(result == CURL_READFUNC_PAUSE)
1435             break;
1436 
1437           if(result == 0)                        /* no bytes */
1438             break;
1439 
1440           readfile_read = result; /* fall thru with number of bytes read */
1441         }
1442         else {
1443           /* read from stdin */
1444           if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL,
1445                             &readfile_read, NULL)) {
1446             keepon = FALSE;
1447             result = CURLE_READ_ERROR;
1448             break;
1449           }
1450 
1451           if(!readfile_read)
1452             break;
1453 
1454           if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
1455                        &readfile_read, NULL)) {
1456             keepon = FALSE;
1457             result = CURLE_READ_ERROR;
1458             break;
1459           }
1460         }
1461 
1462         result = send_telnet_data(conn, buf, readfile_read);
1463         if(result) {
1464           keepon = FALSE;
1465           break;
1466         }
1467       }
1468     }
1469     break;
1470 
1471     case WAIT_OBJECT_0 + 1:
1472     {
1473       if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
1474                    &readfile_read, NULL)) {
1475         keepon = FALSE;
1476         result = CURLE_READ_ERROR;
1477         break;
1478       }
1479 
1480       result = send_telnet_data(conn, buf, readfile_read);
1481       if(result) {
1482         keepon = FALSE;
1483         break;
1484       }
1485     }
1486     break;
1487 
1488     case WAIT_OBJECT_0:
1489 
1490       events.lNetworkEvents = 0;
1491       if(SOCKET_ERROR == enum_netevents_func(sockfd, event_handle, &events)) {
1492         if((err = SOCKERRNO) != EINPROGRESS) {
1493           infof(data, "WSAEnumNetworkEvents failed (%d)", err);
1494           keepon = FALSE;
1495           result = CURLE_READ_ERROR;
1496         }
1497         break;
1498       }
1499       if(events.lNetworkEvents & FD_READ) {
1500         /* read data from network */
1501         result = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
1502         /* read would've blocked. Loop again */
1503         if(result == CURLE_AGAIN)
1504           break;
1505         /* returned not-zero, this an error */
1506         else if(result) {
1507           keepon = FALSE;
1508           break;
1509         }
1510         /* returned zero but actually received 0 or less here,
1511            the server closed the connection and we bail out */
1512         else if(nread <= 0) {
1513           keepon = FALSE;
1514           break;
1515         }
1516 
1517         result = telrcv(conn, (unsigned char *) buf, nread);
1518         if(result) {
1519           keepon = FALSE;
1520           break;
1521         }
1522 
1523         /* Negotiate if the peer has started negotiating,
1524            otherwise don't. We don't want to speak telnet with
1525            non-telnet servers, like POP or SMTP. */
1526         if(tn->please_negotiate && !tn->already_negotiated) {
1527           negotiate(conn);
1528           tn->already_negotiated = 1;
1529         }
1530       }
1531       if(events.lNetworkEvents & FD_CLOSE) {
1532         keepon = FALSE;
1533       }
1534       break;
1535 
1536     }
1537 
1538     if(data->set.timeout) {
1539       now = Curl_tvnow();
1540       if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
1541         failf(data, "Time-out");
1542         result = CURLE_OPERATION_TIMEDOUT;
1543         keepon = FALSE;
1544       }
1545     }
1546   }
1547 
1548   /* We called WSACreateEvent, so call WSACloseEvent */
1549   if(!close_event_func(event_handle)) {
1550     infof(data, "WSACloseEvent failed (%d)", SOCKERRNO);
1551   }
1552 
1553   /* "Forget" pointers into the library we're about to free */
1554   create_event_func = NULL;
1555   close_event_func = NULL;
1556   event_select_func = NULL;
1557   enum_netevents_func = NULL;
1558 
1559   /* We called LoadLibrary, so call FreeLibrary */
1560   if(!FreeLibrary(wsock2))
1561     infof(data, "FreeLibrary(wsock2) failed (%d)", ERRNO);
1562 #else
1563   pfd[0].fd = sockfd;
1564   pfd[0].events = POLLIN;
1565 
1566   if(data->set.fread_func != (curl_read_callback)fread) {
1567     poll_cnt = 1;
1568     interval_ms = 100; /* poll user-supplied read function */
1569   }
1570   else {
1571     /* really using fread, so infile is a FILE* */
1572     pfd[1].fd = fileno((FILE *)data->set.in);
1573     pfd[1].events = POLLIN;
1574     poll_cnt = 2;
1575     interval_ms = 1 * 1000;
1576   }
1577 
1578   while(keepon) {
1579     switch (Curl_poll(pfd, poll_cnt, interval_ms)) {
1580     case -1:                    /* error, stop reading */
1581       keepon = FALSE;
1582       continue;
1583     case 0:                     /* timeout */
1584       pfd[0].revents = 0;
1585       pfd[1].revents = 0;
1586       /* fall through */
1587     default:                    /* read! */
1588       if(pfd[0].revents & POLLIN) {
1589         /* read data from network */
1590         result = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
1591         /* read would've blocked. Loop again */
1592         if(result == CURLE_AGAIN)
1593           break;
1594         /* returned not-zero, this an error */
1595         else if(result) {
1596           keepon = FALSE;
1597           break;
1598         }
1599         /* returned zero but actually received 0 or less here,
1600            the server closed the connection and we bail out */
1601         else if(nread <= 0) {
1602           keepon = FALSE;
1603           break;
1604         }
1605 
1606         total_dl += nread;
1607         Curl_pgrsSetDownloadCounter(data, total_dl);
1608         result = telrcv(conn, (unsigned char *)buf, nread);
1609         if(result) {
1610           keepon = FALSE;
1611           break;
1612         }
1613 
1614         /* Negotiate if the peer has started negotiating,
1615            otherwise don't. We don't want to speak telnet with
1616            non-telnet servers, like POP or SMTP. */
1617         if(tn->please_negotiate && !tn->already_negotiated) {
1618           negotiate(conn);
1619           tn->already_negotiated = 1;
1620         }
1621       }
1622 
1623       nread = 0;
1624       if(poll_cnt == 2) {
1625         if(pfd[1].revents & POLLIN) { /* read from in file */
1626           nread = read(pfd[1].fd, buf, BUFSIZE - 1);
1627         }
1628       }
1629       else {
1630         /* read from user-supplied method */
1631         nread = (int)data->set.fread_func(buf, 1, BUFSIZE - 1, data->set.in);
1632         if(nread == CURL_READFUNC_ABORT) {
1633           keepon = FALSE;
1634           break;
1635         }
1636         if(nread == CURL_READFUNC_PAUSE)
1637           break;
1638       }
1639 
1640       if(nread > 0) {
1641         result = send_telnet_data(conn, buf, nread);
1642         if(result) {
1643           keepon = FALSE;
1644           break;
1645         }
1646         total_ul += nread;
1647         Curl_pgrsSetUploadCounter(data, total_ul);
1648       }
1649       else if(nread < 0)
1650         keepon = FALSE;
1651 
1652       break;
1653     } /* poll switch statement */
1654 
1655     if(data->set.timeout) {
1656       now = Curl_tvnow();
1657       if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
1658         failf(data, "Time-out");
1659         result = CURLE_OPERATION_TIMEDOUT;
1660         keepon = FALSE;
1661       }
1662     }
1663 
1664     if(Curl_pgrsUpdate(conn)) {
1665       result = CURLE_ABORTED_BY_CALLBACK;
1666       break;
1667     }
1668   }
1669 #endif
1670   /* mark this as "no further transfer wanted" */
1671   Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1672 
1673   return result;
1674 }
1675 #endif
1676