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