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