telnet.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                  _   _ ____  _
00003  *  Project                     ___| | | |  _ \| |
00004  *                             / __| | | | |_) | |
00005  *                            | (__| |_| |  _ <| |___
00006  *                             \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
00009  *
00010  * This software is licensed as described in the file COPYING, which
00011  * you should have received as part of this distribution. The terms
00012  * are also available at https://curl.haxx.se/docs/copyright.html.
00013  *
00014  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00015  * copies of the Software, and permit persons to whom the Software is
00016  * furnished to do so, under the terms of the COPYING file.
00017  *
00018  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00019  * KIND, either express or implied.
00020  *
00021  ***************************************************************************/
00022 
00023 #include "curl_setup.h"
00024 
00025 #ifndef CURL_DISABLE_TELNET
00026 
00027 #ifdef HAVE_NETINET_IN_H
00028 #include <netinet/in.h>
00029 #endif
00030 #ifdef HAVE_NETDB_H
00031 #include <netdb.h>
00032 #endif
00033 #ifdef HAVE_ARPA_INET_H
00034 #include <arpa/inet.h>
00035 #endif
00036 #ifdef HAVE_NET_IF_H
00037 #include <net/if.h>
00038 #endif
00039 #ifdef HAVE_SYS_IOCTL_H
00040 #include <sys/ioctl.h>
00041 #endif
00042 
00043 #ifdef HAVE_SYS_PARAM_H
00044 #include <sys/param.h>
00045 #endif
00046 
00047 #include "urldata.h"
00048 #include <curl/curl.h>
00049 #include "transfer.h"
00050 #include "sendf.h"
00051 #include "telnet.h"
00052 #include "connect.h"
00053 #include "progress.h"
00054 #include "system_win32.h"
00055 
00056 #define  TELOPTS
00057 #define  TELCMDS
00058 
00059 #include "arpa_telnet.h"
00060 #include "select.h"
00061 #include "strcase.h"
00062 #include "warnless.h"
00063 
00064 /* The last 3 #include files should be in this order */
00065 #include "curl_printf.h"
00066 #include "curl_memory.h"
00067 #include "memdebug.h"
00068 
00069 #define SUBBUFSIZE 512
00070 
00071 #define CURL_SB_CLEAR(x)  x->subpointer = x->subbuffer
00072 #define CURL_SB_TERM(x)                                 \
00073   do {                                                  \
00074     x->subend = x->subpointer;                          \
00075     CURL_SB_CLEAR(x);                                   \
00076   } WHILE_FALSE
00077 #define CURL_SB_ACCUM(x,c)                                   \
00078   do {                                                       \
00079     if(x->subpointer < (x->subbuffer+sizeof x->subbuffer))   \
00080       *x->subpointer++ = (c);                                \
00081   } WHILE_FALSE
00082 
00083 #define  CURL_SB_GET(x) ((*x->subpointer++)&0xff)
00084 #define  CURL_SB_PEEK(x)   ((*x->subpointer)&0xff)
00085 #define  CURL_SB_EOF(x) (x->subpointer >= x->subend)
00086 #define  CURL_SB_LEN(x) (x->subend - x->subpointer)
00087 
00088 #ifdef CURL_DISABLE_VERBOSE_STRINGS
00089 #define printoption(a,b,c,d)  Curl_nop_stmt
00090 #endif
00091 
00092 #ifdef USE_WINSOCK
00093 typedef FARPROC WSOCK2_FUNC;
00094 static CURLcode check_wsock2(struct Curl_easy *data);
00095 #endif
00096 
00097 static
00098 CURLcode telrcv(struct connectdata *,
00099                 const unsigned char *inbuf, /* Data received from socket */
00100                 ssize_t count);             /* Number of bytes received */
00101 
00102 #ifndef CURL_DISABLE_VERBOSE_STRINGS
00103 static void printoption(struct Curl_easy *data,
00104                         const char *direction,
00105                         int cmd, int option);
00106 #endif
00107 
00108 static void negotiate(struct connectdata *);
00109 static void send_negotiation(struct connectdata *, int cmd, int option);
00110 static void set_local_option(struct connectdata *, int cmd, int option);
00111 static void set_remote_option(struct connectdata *, int cmd, int option);
00112 
00113 static void printsub(struct Curl_easy *data,
00114                      int direction, unsigned char *pointer,
00115                      size_t length);
00116 static void suboption(struct connectdata *);
00117 static void sendsuboption(struct connectdata *conn, int option);
00118 
00119 static CURLcode telnet_do(struct connectdata *conn, bool *done);
00120 static CURLcode telnet_done(struct connectdata *conn,
00121                                  CURLcode, bool premature);
00122 static CURLcode send_telnet_data(struct connectdata *conn,
00123                                  char *buffer, ssize_t nread);
00124 
00125 /* For negotiation compliant to RFC 1143 */
00126 #define CURL_NO          0
00127 #define CURL_YES         1
00128 #define CURL_WANTYES     2
00129 #define CURL_WANTNO      3
00130 
00131 #define CURL_EMPTY       0
00132 #define CURL_OPPOSITE    1
00133 
00134 /*
00135  * Telnet receiver states for fsm
00136  */
00137 typedef enum
00138 {
00139    CURL_TS_DATA = 0,
00140    CURL_TS_IAC,
00141    CURL_TS_WILL,
00142    CURL_TS_WONT,
00143    CURL_TS_DO,
00144    CURL_TS_DONT,
00145    CURL_TS_CR,
00146    CURL_TS_SB,   /* sub-option collection */
00147    CURL_TS_SE   /* looking for sub-option end */
00148 } TelnetReceive;
00149 
00150 struct TELNET {
00151   int please_negotiate;
00152   int already_negotiated;
00153   int us[256];
00154   int usq[256];
00155   int us_preferred[256];
00156   int him[256];
00157   int himq[256];
00158   int him_preferred[256];
00159   int subnegotiation[256];
00160   char subopt_ttype[32];             /* Set with suboption TTYPE */
00161   char subopt_xdisploc[128];         /* Set with suboption XDISPLOC */
00162   unsigned short subopt_wsx;         /* Set with suboption NAWS */
00163   unsigned short subopt_wsy;         /* Set with suboption NAWS */
00164   struct curl_slist *telnet_vars;    /* Environment variables */
00165 
00166   /* suboptions */
00167   unsigned char subbuffer[SUBBUFSIZE];
00168   unsigned char *subpointer, *subend;      /* buffer for sub-options */
00169 
00170   TelnetReceive telrcv_state;
00171 };
00172 
00173 
00174 /*
00175  * TELNET protocol handler.
00176  */
00177 
00178 const struct Curl_handler Curl_handler_telnet = {
00179   "TELNET",                             /* scheme */
00180   ZERO_NULL,                            /* setup_connection */
00181   telnet_do,                            /* do_it */
00182   telnet_done,                          /* done */
00183   ZERO_NULL,                            /* do_more */
00184   ZERO_NULL,                            /* connect_it */
00185   ZERO_NULL,                            /* connecting */
00186   ZERO_NULL,                            /* doing */
00187   ZERO_NULL,                            /* proto_getsock */
00188   ZERO_NULL,                            /* doing_getsock */
00189   ZERO_NULL,                            /* domore_getsock */
00190   ZERO_NULL,                            /* perform_getsock */
00191   ZERO_NULL,                            /* disconnect */
00192   ZERO_NULL,                            /* readwrite */
00193   PORT_TELNET,                          /* defport */
00194   CURLPROTO_TELNET,                     /* protocol */
00195   PROTOPT_NONE | PROTOPT_NOURLQUERY     /* flags */
00196 };
00197 
00198 
00199 #ifdef USE_WINSOCK
00200 static CURLcode
00201 check_wsock2(struct Curl_easy *data)
00202 {
00203   int err;
00204   WORD wVersionRequested;
00205   WSADATA wsaData;
00206 
00207   DEBUGASSERT(data);
00208 
00209   /* telnet requires at least WinSock 2.0 so ask for it. */
00210   wVersionRequested = MAKEWORD(2, 0);
00211 
00212   err = WSAStartup(wVersionRequested, &wsaData);
00213 
00214   /* We must've called this once already, so this call */
00215   /* should always succeed.  But, just in case... */
00216   if(err != 0) {
00217     failf(data,"WSAStartup failed (%d)",err);
00218     return CURLE_FAILED_INIT;
00219   }
00220 
00221   /* We have to have a WSACleanup call for every successful */
00222   /* WSAStartup call. */
00223   WSACleanup();
00224 
00225   /* Check that our version is supported */
00226   if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
00227       HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested)) {
00228       /* Our version isn't supported */
00229     failf(data, "insufficient winsock version to support "
00230           "telnet");
00231     return CURLE_FAILED_INIT;
00232   }
00233 
00234   /* Our version is supported */
00235   return CURLE_OK;
00236 }
00237 #endif
00238 
00239 static
00240 CURLcode init_telnet(struct connectdata *conn)
00241 {
00242   struct TELNET *tn;
00243 
00244   tn = calloc(1, sizeof(struct TELNET));
00245   if(!tn)
00246     return CURLE_OUT_OF_MEMORY;
00247 
00248   conn->data->req.protop = tn; /* make us known */
00249 
00250   tn->telrcv_state = CURL_TS_DATA;
00251 
00252   /* Init suboptions */
00253   CURL_SB_CLEAR(tn);
00254 
00255   /* Set the options we want by default */
00256   tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES;
00257   tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES;
00258 
00259   /* To be compliant with previous releases of libcurl
00260      we enable this option by default. This behaviour
00261          can be changed thanks to the "BINARY" option in
00262          CURLOPT_TELNETOPTIONS
00263   */
00264   tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES;
00265   tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES;
00266 
00267   /* We must allow the server to echo what we sent
00268          but it is not necessary to request the server
00269          to do so (it might forces the server to close
00270          the connection). Hence, we ignore ECHO in the
00271          negotiate function
00272   */
00273   tn->him_preferred[CURL_TELOPT_ECHO] = CURL_YES;
00274 
00275   /* Set the subnegotiation fields to send information
00276     just after negotiation passed (do/will)
00277 
00278      Default values are (0,0) initialized by calloc.
00279      According to the RFC1013 it is valid:
00280      A value equal to zero is acceptable for the width (or height),
00281          and means that no character width (or height) is being sent.
00282          In this case, the width (or height) that will be assumed by the
00283          Telnet server is operating system specific (it will probably be
00284          based upon the terminal type information that may have been sent
00285          using the TERMINAL TYPE Telnet option). */
00286   tn->subnegotiation[CURL_TELOPT_NAWS] = CURL_YES;
00287   return CURLE_OK;
00288 }
00289 
00290 static void negotiate(struct connectdata *conn)
00291 {
00292   int i;
00293   struct TELNET *tn = (struct TELNET *) conn->data->req.protop;
00294 
00295   for(i = 0;i < CURL_NTELOPTS;i++) {
00296     if(i==CURL_TELOPT_ECHO)
00297       continue;
00298 
00299     if(tn->us_preferred[i] == CURL_YES)
00300       set_local_option(conn, i, CURL_YES);
00301 
00302     if(tn->him_preferred[i] == CURL_YES)
00303       set_remote_option(conn, i, CURL_YES);
00304   }
00305 }
00306 
00307 #ifndef CURL_DISABLE_VERBOSE_STRINGS
00308 static void printoption(struct Curl_easy *data,
00309                         const char *direction, int cmd, int option)
00310 {
00311   const char *fmt;
00312   const char *opt;
00313 
00314   if(data->set.verbose) {
00315     if(cmd == CURL_IAC) {
00316       if(CURL_TELCMD_OK(option))
00317         infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option));
00318       else
00319         infof(data, "%s IAC %d\n", direction, option);
00320     }
00321     else {
00322       fmt = (cmd == CURL_WILL) ? "WILL" : (cmd == CURL_WONT) ? "WONT" :
00323         (cmd == CURL_DO) ? "DO" : (cmd == CURL_DONT) ? "DONT" : 0;
00324       if(fmt) {
00325         if(CURL_TELOPT_OK(option))
00326           opt = CURL_TELOPT(option);
00327         else if(option == CURL_TELOPT_EXOPL)
00328           opt = "EXOPL";
00329         else
00330           opt = NULL;
00331 
00332         if(opt)
00333           infof(data, "%s %s %s\n", direction, fmt, opt);
00334         else
00335           infof(data, "%s %s %d\n", direction, fmt, option);
00336       }
00337       else
00338         infof(data, "%s %d %d\n", direction, cmd, option);
00339     }
00340   }
00341 }
00342 #endif
00343 
00344 static void send_negotiation(struct connectdata *conn, int cmd, int option)
00345 {
00346    unsigned char buf[3];
00347    ssize_t bytes_written;
00348    int err;
00349    struct Curl_easy *data = conn->data;
00350 
00351    buf[0] = CURL_IAC;
00352    buf[1] = (unsigned char)cmd;
00353    buf[2] = (unsigned char)option;
00354 
00355    bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3);
00356    if(bytes_written < 0) {
00357      err = SOCKERRNO;
00358      failf(data,"Sending data failed (%d)",err);
00359    }
00360 
00361    printoption(conn->data, "SENT", cmd, option);
00362 }
00363 
00364 static
00365 void set_remote_option(struct connectdata *conn, int option, int newstate)
00366 {
00367   struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
00368   if(newstate == CURL_YES) {
00369     switch(tn->him[option]) {
00370     case CURL_NO:
00371       tn->him[option] = CURL_WANTYES;
00372       send_negotiation(conn, CURL_DO, option);
00373       break;
00374 
00375     case CURL_YES:
00376       /* Already enabled */
00377       break;
00378 
00379     case CURL_WANTNO:
00380       switch(tn->himq[option]) {
00381       case CURL_EMPTY:
00382         /* Already negotiating for CURL_YES, queue the request */
00383         tn->himq[option] = CURL_OPPOSITE;
00384         break;
00385       case CURL_OPPOSITE:
00386         /* Error: already queued an enable request */
00387         break;
00388       }
00389       break;
00390 
00391     case CURL_WANTYES:
00392       switch(tn->himq[option]) {
00393       case CURL_EMPTY:
00394         /* Error: already negotiating for enable */
00395         break;
00396       case CURL_OPPOSITE:
00397         tn->himq[option] = CURL_EMPTY;
00398         break;
00399       }
00400       break;
00401     }
00402   }
00403   else { /* NO */
00404     switch(tn->him[option]) {
00405     case CURL_NO:
00406       /* Already disabled */
00407       break;
00408 
00409     case CURL_YES:
00410       tn->him[option] = CURL_WANTNO;
00411       send_negotiation(conn, CURL_DONT, option);
00412       break;
00413 
00414     case CURL_WANTNO:
00415       switch(tn->himq[option]) {
00416       case CURL_EMPTY:
00417         /* Already negotiating for NO */
00418         break;
00419       case CURL_OPPOSITE:
00420         tn->himq[option] = CURL_EMPTY;
00421         break;
00422       }
00423       break;
00424 
00425     case CURL_WANTYES:
00426       switch(tn->himq[option]) {
00427       case CURL_EMPTY:
00428         tn->himq[option] = CURL_OPPOSITE;
00429         break;
00430       case CURL_OPPOSITE:
00431         break;
00432       }
00433       break;
00434     }
00435   }
00436 }
00437 
00438 static
00439 void rec_will(struct connectdata *conn, int option)
00440 {
00441   struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
00442   switch(tn->him[option]) {
00443   case CURL_NO:
00444     if(tn->him_preferred[option] == CURL_YES) {
00445       tn->him[option] = CURL_YES;
00446       send_negotiation(conn, CURL_DO, option);
00447     }
00448     else
00449       send_negotiation(conn, CURL_DONT, option);
00450 
00451     break;
00452 
00453   case CURL_YES:
00454     /* Already enabled */
00455     break;
00456 
00457   case CURL_WANTNO:
00458     switch(tn->himq[option]) {
00459     case CURL_EMPTY:
00460       /* Error: DONT answered by WILL */
00461       tn->him[option] = CURL_NO;
00462       break;
00463     case CURL_OPPOSITE:
00464       /* Error: DONT answered by WILL */
00465       tn->him[option] = CURL_YES;
00466       tn->himq[option] = CURL_EMPTY;
00467       break;
00468     }
00469     break;
00470 
00471   case CURL_WANTYES:
00472     switch(tn->himq[option]) {
00473     case CURL_EMPTY:
00474       tn->him[option] = CURL_YES;
00475       break;
00476     case CURL_OPPOSITE:
00477       tn->him[option] = CURL_WANTNO;
00478       tn->himq[option] = CURL_EMPTY;
00479       send_negotiation(conn, CURL_DONT, option);
00480       break;
00481     }
00482     break;
00483   }
00484 }
00485 
00486 static
00487 void rec_wont(struct connectdata *conn, int option)
00488 {
00489   struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
00490   switch(tn->him[option]) {
00491   case CURL_NO:
00492     /* Already disabled */
00493     break;
00494 
00495   case CURL_YES:
00496     tn->him[option] = CURL_NO;
00497     send_negotiation(conn, CURL_DONT, option);
00498     break;
00499 
00500   case CURL_WANTNO:
00501     switch(tn->himq[option]) {
00502     case CURL_EMPTY:
00503       tn->him[option] = CURL_NO;
00504       break;
00505 
00506     case CURL_OPPOSITE:
00507       tn->him[option] = CURL_WANTYES;
00508       tn->himq[option] = CURL_EMPTY;
00509       send_negotiation(conn, CURL_DO, option);
00510       break;
00511     }
00512     break;
00513 
00514   case CURL_WANTYES:
00515     switch(tn->himq[option]) {
00516     case CURL_EMPTY:
00517       tn->him[option] = CURL_NO;
00518       break;
00519     case CURL_OPPOSITE:
00520       tn->him[option] = CURL_NO;
00521       tn->himq[option] = CURL_EMPTY;
00522       break;
00523     }
00524     break;
00525   }
00526 }
00527 
00528 static void
00529 set_local_option(struct connectdata *conn, int option, int newstate)
00530 {
00531   struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
00532   if(newstate == CURL_YES) {
00533     switch(tn->us[option]) {
00534     case CURL_NO:
00535       tn->us[option] = CURL_WANTYES;
00536       send_negotiation(conn, CURL_WILL, option);
00537       break;
00538 
00539     case CURL_YES:
00540       /* Already enabled */
00541       break;
00542 
00543     case CURL_WANTNO:
00544       switch(tn->usq[option]) {
00545       case CURL_EMPTY:
00546         /* Already negotiating for CURL_YES, queue the request */
00547         tn->usq[option] = CURL_OPPOSITE;
00548         break;
00549       case CURL_OPPOSITE:
00550         /* Error: already queued an enable request */
00551         break;
00552       }
00553       break;
00554 
00555     case CURL_WANTYES:
00556       switch(tn->usq[option]) {
00557       case CURL_EMPTY:
00558         /* Error: already negotiating for enable */
00559         break;
00560       case CURL_OPPOSITE:
00561         tn->usq[option] = CURL_EMPTY;
00562         break;
00563       }
00564       break;
00565     }
00566   }
00567   else { /* NO */
00568     switch(tn->us[option]) {
00569     case CURL_NO:
00570       /* Already disabled */
00571       break;
00572 
00573     case CURL_YES:
00574       tn->us[option] = CURL_WANTNO;
00575       send_negotiation(conn, CURL_WONT, option);
00576       break;
00577 
00578     case CURL_WANTNO:
00579       switch(tn->usq[option]) {
00580       case CURL_EMPTY:
00581         /* Already negotiating for NO */
00582         break;
00583       case CURL_OPPOSITE:
00584         tn->usq[option] = CURL_EMPTY;
00585         break;
00586       }
00587       break;
00588 
00589     case CURL_WANTYES:
00590       switch(tn->usq[option]) {
00591       case CURL_EMPTY:
00592         tn->usq[option] = CURL_OPPOSITE;
00593         break;
00594       case CURL_OPPOSITE:
00595         break;
00596       }
00597       break;
00598     }
00599   }
00600 }
00601 
00602 static
00603 void rec_do(struct connectdata *conn, int option)
00604 {
00605   struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
00606   switch(tn->us[option]) {
00607   case CURL_NO:
00608     if(tn->us_preferred[option] == CURL_YES) {
00609       tn->us[option] = CURL_YES;
00610       send_negotiation(conn, CURL_WILL, option);
00611       if(tn->subnegotiation[option] == CURL_YES)
00612         /* transmission of data option */
00613         sendsuboption(conn, option);
00614     }
00615     else if(tn->subnegotiation[option] == CURL_YES) {
00616       /* send information to achieve this option*/
00617       tn->us[option] = CURL_YES;
00618       send_negotiation(conn, CURL_WILL, option);
00619       sendsuboption(conn, option);
00620     }
00621     else
00622       send_negotiation(conn, CURL_WONT, option);
00623     break;
00624 
00625   case CURL_YES:
00626     /* Already enabled */
00627     break;
00628 
00629   case CURL_WANTNO:
00630     switch(tn->usq[option]) {
00631     case CURL_EMPTY:
00632       /* Error: DONT answered by WILL */
00633       tn->us[option] = CURL_NO;
00634       break;
00635     case CURL_OPPOSITE:
00636       /* Error: DONT answered by WILL */
00637       tn->us[option] = CURL_YES;
00638       tn->usq[option] = CURL_EMPTY;
00639       break;
00640     }
00641     break;
00642 
00643   case CURL_WANTYES:
00644     switch(tn->usq[option]) {
00645     case CURL_EMPTY:
00646       tn->us[option] = CURL_YES;
00647       if(tn->subnegotiation[option] == CURL_YES) {
00648         /* transmission of data option */
00649         sendsuboption(conn, option);
00650       }
00651       break;
00652     case CURL_OPPOSITE:
00653       tn->us[option] = CURL_WANTNO;
00654       tn->himq[option] = CURL_EMPTY;
00655       send_negotiation(conn, CURL_WONT, option);
00656       break;
00657     }
00658     break;
00659   }
00660 }
00661 
00662 static
00663 void rec_dont(struct connectdata *conn, int option)
00664 {
00665   struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
00666   switch(tn->us[option]) {
00667   case CURL_NO:
00668     /* Already disabled */
00669     break;
00670 
00671   case CURL_YES:
00672     tn->us[option] = CURL_NO;
00673     send_negotiation(conn, CURL_WONT, option);
00674     break;
00675 
00676   case CURL_WANTNO:
00677     switch(tn->usq[option]) {
00678     case CURL_EMPTY:
00679       tn->us[option] = CURL_NO;
00680       break;
00681 
00682     case CURL_OPPOSITE:
00683       tn->us[option] = CURL_WANTYES;
00684       tn->usq[option] = CURL_EMPTY;
00685       send_negotiation(conn, CURL_WILL, option);
00686       break;
00687     }
00688     break;
00689 
00690   case CURL_WANTYES:
00691     switch(tn->usq[option]) {
00692     case CURL_EMPTY:
00693       tn->us[option] = CURL_NO;
00694       break;
00695     case CURL_OPPOSITE:
00696       tn->us[option] = CURL_NO;
00697       tn->usq[option] = CURL_EMPTY;
00698       break;
00699     }
00700     break;
00701   }
00702 }
00703 
00704 
00705 static void printsub(struct Curl_easy *data,
00706                      int direction,             /* '<' or '>' */
00707                      unsigned char *pointer,    /* where suboption data is */
00708                      size_t length)             /* length of suboption data */
00709 {
00710   unsigned int i = 0;
00711 
00712   if(data->set.verbose) {
00713     if(direction) {
00714       infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
00715       if(length >= 3) {
00716         int j;
00717 
00718         i = pointer[length-2];
00719         j = pointer[length-1];
00720 
00721         if(i != CURL_IAC || j != CURL_SE) {
00722           infof(data, "(terminated by ");
00723           if(CURL_TELOPT_OK(i))
00724             infof(data, "%s ", CURL_TELOPT(i));
00725           else if(CURL_TELCMD_OK(i))
00726             infof(data, "%s ", CURL_TELCMD(i));
00727           else
00728             infof(data, "%u ", i);
00729           if(CURL_TELOPT_OK(j))
00730             infof(data, "%s", CURL_TELOPT(j));
00731           else if(CURL_TELCMD_OK(j))
00732             infof(data, "%s", CURL_TELCMD(j));
00733           else
00734             infof(data, "%d", j);
00735           infof(data, ", not IAC SE!) ");
00736         }
00737       }
00738       length -= 2;
00739     }
00740     if(length < 1) {
00741       infof(data, "(Empty suboption?)");
00742       return;
00743     }
00744 
00745     if(CURL_TELOPT_OK(pointer[0])) {
00746       switch(pointer[0]) {
00747       case CURL_TELOPT_TTYPE:
00748       case CURL_TELOPT_XDISPLOC:
00749       case CURL_TELOPT_NEW_ENVIRON:
00750       case CURL_TELOPT_NAWS:
00751         infof(data, "%s", CURL_TELOPT(pointer[0]));
00752         break;
00753       default:
00754         infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
00755         break;
00756       }
00757     }
00758     else
00759       infof(data, "%d (unknown)", pointer[i]);
00760 
00761     switch(pointer[0]) {
00762     case CURL_TELOPT_NAWS:
00763       if(length > 4)
00764         infof(data, "Width: %hu ; Height: %hu", (pointer[1]<<8) | pointer[2],
00765               (pointer[3]<<8) | pointer[4]);
00766       break;
00767     default:
00768       switch(pointer[1]) {
00769       case CURL_TELQUAL_IS:
00770         infof(data, " IS");
00771         break;
00772       case CURL_TELQUAL_SEND:
00773         infof(data, " SEND");
00774         break;
00775       case CURL_TELQUAL_INFO:
00776         infof(data, " INFO/REPLY");
00777         break;
00778       case CURL_TELQUAL_NAME:
00779         infof(data, " NAME");
00780         break;
00781       }
00782 
00783       switch(pointer[0]) {
00784       case CURL_TELOPT_TTYPE:
00785       case CURL_TELOPT_XDISPLOC:
00786         pointer[length] = 0;
00787         infof(data, " \"%s\"", &pointer[2]);
00788         break;
00789       case CURL_TELOPT_NEW_ENVIRON:
00790         if(pointer[1] == CURL_TELQUAL_IS) {
00791           infof(data, " ");
00792           for(i = 3;i < length;i++) {
00793             switch(pointer[i]) {
00794             case CURL_NEW_ENV_VAR:
00795               infof(data, ", ");
00796               break;
00797             case CURL_NEW_ENV_VALUE:
00798               infof(data, " = ");
00799               break;
00800             default:
00801               infof(data, "%c", pointer[i]);
00802               break;
00803             }
00804           }
00805         }
00806         break;
00807       default:
00808         for(i = 2; i < length; i++)
00809           infof(data, " %.2x", pointer[i]);
00810         break;
00811       }
00812     }
00813     if(direction)
00814       infof(data, "\n");
00815   }
00816 }
00817 
00818 static CURLcode check_telnet_options(struct connectdata *conn)
00819 {
00820   struct curl_slist *head;
00821   struct curl_slist *beg;
00822   char option_keyword[128] = "";
00823   char option_arg[256] = "";
00824   struct Curl_easy *data = conn->data;
00825   struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
00826   CURLcode result = CURLE_OK;
00827   int binary_option;
00828 
00829   /* Add the user name as an environment variable if it
00830      was given on the command line */
00831   if(conn->bits.user_passwd) {
00832     snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
00833     beg = curl_slist_append(tn->telnet_vars, option_arg);
00834     if(!beg) {
00835       curl_slist_free_all(tn->telnet_vars);
00836       tn->telnet_vars = NULL;
00837       return CURLE_OUT_OF_MEMORY;
00838     }
00839     tn->telnet_vars = beg;
00840     tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
00841   }
00842 
00843   for(head = data->set.telnet_options; head; head=head->next) {
00844     if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
00845               option_keyword, option_arg) == 2) {
00846 
00847       /* Terminal type */
00848       if(strcasecompare(option_keyword, "TTYPE")) {
00849         strncpy(tn->subopt_ttype, option_arg, 31);
00850         tn->subopt_ttype[31] = 0; /* String termination */
00851         tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
00852         continue;
00853       }
00854 
00855       /* Display variable */
00856       if(strcasecompare(option_keyword, "XDISPLOC")) {
00857         strncpy(tn->subopt_xdisploc, option_arg, 127);
00858         tn->subopt_xdisploc[127] = 0; /* String termination */
00859         tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
00860         continue;
00861       }
00862 
00863       /* Environment variable */
00864       if(strcasecompare(option_keyword, "NEW_ENV")) {
00865         beg = curl_slist_append(tn->telnet_vars, option_arg);
00866         if(!beg) {
00867           result = CURLE_OUT_OF_MEMORY;
00868           break;
00869         }
00870         tn->telnet_vars = beg;
00871         tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
00872         continue;
00873       }
00874 
00875           /* Window Size */
00876       if(strcasecompare(option_keyword, "WS")) {
00877         if(sscanf(option_arg, "%hu%*[xX]%hu",
00878                   &tn->subopt_wsx, &tn->subopt_wsy) == 2)
00879           tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
00880         else {
00881           failf(data, "Syntax error in telnet option: %s", head->data);
00882           result = CURLE_TELNET_OPTION_SYNTAX;
00883           break;
00884         }
00885         continue;
00886       }
00887 
00888       /* To take care or not of the 8th bit in data exchange */
00889       if(strcasecompare(option_keyword, "BINARY")) {
00890         binary_option=atoi(option_arg);
00891         if(binary_option!=1) {
00892           tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO;
00893           tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO;
00894         }
00895         continue;
00896       }
00897 
00898       failf(data, "Unknown telnet option %s", head->data);
00899       result = CURLE_UNKNOWN_TELNET_OPTION;
00900       break;
00901     }
00902     else {
00903       failf(data, "Syntax error in telnet option: %s", head->data);
00904       result = CURLE_TELNET_OPTION_SYNTAX;
00905       break;
00906     }
00907   }
00908 
00909   if(result) {
00910     curl_slist_free_all(tn->telnet_vars);
00911     tn->telnet_vars = NULL;
00912   }
00913 
00914   return result;
00915 }
00916 
00917 /*
00918  * suboption()
00919  *
00920  * Look at the sub-option buffer, and try to be helpful to the other
00921  * side.
00922  */
00923 
00924 static void suboption(struct connectdata *conn)
00925 {
00926   struct curl_slist *v;
00927   unsigned char temp[2048];
00928   ssize_t bytes_written;
00929   size_t len;
00930   size_t tmplen;
00931   int err;
00932   char varname[128] = "";
00933   char varval[128] = "";
00934   struct Curl_easy *data = conn->data;
00935   struct TELNET *tn = (struct TELNET *)data->req.protop;
00936 
00937   printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn)+2);
00938   switch(CURL_SB_GET(tn)) {
00939     case CURL_TELOPT_TTYPE:
00940       len = strlen(tn->subopt_ttype) + 4 + 2;
00941       snprintf((char *)temp, sizeof(temp),
00942                "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
00943                CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE);
00944       bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
00945       if(bytes_written < 0) {
00946         err = SOCKERRNO;
00947         failf(data,"Sending data failed (%d)",err);
00948       }
00949       printsub(data, '>', &temp[2], len-2);
00950       break;
00951     case CURL_TELOPT_XDISPLOC:
00952       len = strlen(tn->subopt_xdisploc) + 4 + 2;
00953       snprintf((char *)temp, sizeof(temp),
00954                "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
00955                CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE);
00956       bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
00957       if(bytes_written < 0) {
00958         err = SOCKERRNO;
00959         failf(data,"Sending data failed (%d)",err);
00960       }
00961       printsub(data, '>', &temp[2], len-2);
00962       break;
00963     case CURL_TELOPT_NEW_ENVIRON:
00964       snprintf((char *)temp, sizeof(temp),
00965                "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON,
00966                CURL_TELQUAL_IS);
00967       len = 4;
00968 
00969       for(v = tn->telnet_vars;v;v = v->next) {
00970         tmplen = (strlen(v->data) + 1);
00971         /* Add the variable only if it fits */
00972         if(len + tmplen < (int)sizeof(temp)-6) {
00973           if(sscanf(v->data, "%127[^,],%127s", varname, varval)) {
00974             snprintf((char *)&temp[len], sizeof(temp) - len,
00975                      "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
00976                      CURL_NEW_ENV_VALUE, varval);
00977             len += tmplen;
00978           }
00979         }
00980       }
00981       snprintf((char *)&temp[len], sizeof(temp) - len,
00982                "%c%c", CURL_IAC, CURL_SE);
00983       len += 2;
00984       bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
00985       if(bytes_written < 0) {
00986         err = SOCKERRNO;
00987         failf(data,"Sending data failed (%d)",err);
00988       }
00989       printsub(data, '>', &temp[2], len-2);
00990       break;
00991   }
00992   return;
00993 }
00994 
00995 
00996 /*
00997  * sendsuboption()
00998  *
00999  * Send suboption information to the server side.
01000  */
01001 
01002 static void sendsuboption(struct connectdata *conn, int option)
01003 {
01004   ssize_t bytes_written;
01005   int err;
01006   unsigned short x, y;
01007   unsigned char *uc1, *uc2;
01008 
01009   struct Curl_easy *data = conn->data;
01010   struct TELNET *tn = (struct TELNET *)data->req.protop;
01011 
01012   switch(option) {
01013   case CURL_TELOPT_NAWS:
01014     /* We prepare data to be sent */
01015     CURL_SB_CLEAR(tn);
01016     CURL_SB_ACCUM(tn, CURL_IAC);
01017     CURL_SB_ACCUM(tn, CURL_SB);
01018     CURL_SB_ACCUM(tn, CURL_TELOPT_NAWS);
01019     /* We must deal either with litte or big endien processors */
01020     /* Window size must be sent according to the 'network order' */
01021     x=htons(tn->subopt_wsx);
01022     y=htons(tn->subopt_wsy);
01023     uc1 = (unsigned char *)&x;
01024     uc2 = (unsigned char *)&y;
01025     CURL_SB_ACCUM(tn, uc1[0]);
01026     CURL_SB_ACCUM(tn, uc1[1]);
01027     CURL_SB_ACCUM(tn, uc2[0]);
01028     CURL_SB_ACCUM(tn, uc2[1]);
01029 
01030     CURL_SB_ACCUM(tn, CURL_IAC);
01031     CURL_SB_ACCUM(tn, CURL_SE);
01032     CURL_SB_TERM(tn);
01033     /* data suboption is now ready */
01034 
01035     printsub(data, '>', (unsigned char *)tn->subbuffer+2,
01036              CURL_SB_LEN(tn)-2);
01037 
01038     /* we send the header of the suboption... */
01039     bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer, 3);
01040     if(bytes_written < 0) {
01041       err = SOCKERRNO;
01042       failf(data, "Sending data failed (%d)", err);
01043     }
01044     /* ... then the window size with the send_telnet_data() function
01045        to deal with 0xFF cases ... */
01046     send_telnet_data(conn, (char *)tn->subbuffer+3, 4);
01047     /* ... and the footer */
01048     bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer+7, 2);
01049     if(bytes_written < 0) {
01050       err = SOCKERRNO;
01051       failf(data, "Sending data failed (%d)", err);
01052     }
01053     break;
01054   }
01055 }
01056 
01057 
01058 static
01059 CURLcode telrcv(struct connectdata *conn,
01060                 const unsigned char *inbuf, /* Data received from socket */
01061                 ssize_t count)              /* Number of bytes received */
01062 {
01063   unsigned char c;
01064   CURLcode result;
01065   int in = 0;
01066   int startwrite=-1;
01067   struct Curl_easy *data = conn->data;
01068   struct TELNET *tn = (struct TELNET *)data->req.protop;
01069 
01070 #define startskipping()                                       \
01071   if(startwrite >= 0) {                                       \
01072     result = Curl_client_write(conn,                          \
01073                                CLIENTWRITE_BODY,              \
01074                                (char *)&inbuf[startwrite],    \
01075                                in-startwrite);                \
01076     if(result)                                                \
01077       return result;                                          \
01078   }                                                           \
01079   startwrite = -1
01080 
01081 #define writebyte() \
01082     if(startwrite < 0) \
01083       startwrite = in
01084 
01085 #define bufferflush() startskipping()
01086 
01087   while(count--) {
01088     c = inbuf[in];
01089 
01090     switch(tn->telrcv_state) {
01091     case CURL_TS_CR:
01092       tn->telrcv_state = CURL_TS_DATA;
01093       if(c == '\0') {
01094         startskipping();
01095         break;   /* Ignore \0 after CR */
01096       }
01097       writebyte();
01098       break;
01099 
01100     case CURL_TS_DATA:
01101       if(c == CURL_IAC) {
01102         tn->telrcv_state = CURL_TS_IAC;
01103         startskipping();
01104         break;
01105       }
01106       else if(c == '\r')
01107         tn->telrcv_state = CURL_TS_CR;
01108       writebyte();
01109       break;
01110 
01111     case CURL_TS_IAC:
01112     process_iac:
01113       DEBUGASSERT(startwrite < 0);
01114       switch(c) {
01115       case CURL_WILL:
01116         tn->telrcv_state = CURL_TS_WILL;
01117         break;
01118       case CURL_WONT:
01119         tn->telrcv_state = CURL_TS_WONT;
01120         break;
01121       case CURL_DO:
01122         tn->telrcv_state = CURL_TS_DO;
01123         break;
01124       case CURL_DONT:
01125         tn->telrcv_state = CURL_TS_DONT;
01126         break;
01127       case CURL_SB:
01128         CURL_SB_CLEAR(tn);
01129         tn->telrcv_state = CURL_TS_SB;
01130         break;
01131       case CURL_IAC:
01132         tn->telrcv_state = CURL_TS_DATA;
01133         writebyte();
01134         break;
01135       case CURL_DM:
01136       case CURL_NOP:
01137       case CURL_GA:
01138       default:
01139         tn->telrcv_state = CURL_TS_DATA;
01140         printoption(data, "RCVD", CURL_IAC, c);
01141         break;
01142       }
01143       break;
01144 
01145       case CURL_TS_WILL:
01146         printoption(data, "RCVD", CURL_WILL, c);
01147         tn->please_negotiate = 1;
01148         rec_will(conn, c);
01149         tn->telrcv_state = CURL_TS_DATA;
01150         break;
01151 
01152       case CURL_TS_WONT:
01153         printoption(data, "RCVD", CURL_WONT, c);
01154         tn->please_negotiate = 1;
01155         rec_wont(conn, c);
01156         tn->telrcv_state = CURL_TS_DATA;
01157         break;
01158 
01159       case CURL_TS_DO:
01160         printoption(data, "RCVD", CURL_DO, c);
01161         tn->please_negotiate = 1;
01162         rec_do(conn, c);
01163         tn->telrcv_state = CURL_TS_DATA;
01164         break;
01165 
01166       case CURL_TS_DONT:
01167         printoption(data, "RCVD", CURL_DONT, c);
01168         tn->please_negotiate = 1;
01169         rec_dont(conn, c);
01170         tn->telrcv_state = CURL_TS_DATA;
01171         break;
01172 
01173       case CURL_TS_SB:
01174         if(c == CURL_IAC)
01175           tn->telrcv_state = CURL_TS_SE;
01176         else
01177           CURL_SB_ACCUM(tn, c);
01178         break;
01179 
01180       case CURL_TS_SE:
01181         if(c != CURL_SE) {
01182           if(c != CURL_IAC) {
01183             /*
01184              * This is an error.  We only expect to get "IAC IAC" or "IAC SE".
01185              * Several things may have happened.  An IAC was not doubled, the
01186              * IAC SE was left off, or another option got inserted into the
01187              * suboption are all possibilities.  If we assume that the IAC was
01188              * not doubled, and really the IAC SE was left off, we could get
01189              * into an infinate loop here.  So, instead, we terminate the
01190              * suboption, and process the partial suboption if we can.
01191              */
01192             CURL_SB_ACCUM(tn, CURL_IAC);
01193             CURL_SB_ACCUM(tn, c);
01194             tn->subpointer -= 2;
01195             CURL_SB_TERM(tn);
01196 
01197             printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c);
01198             suboption(conn);   /* handle sub-option */
01199             tn->telrcv_state = CURL_TS_IAC;
01200             goto process_iac;
01201           }
01202           CURL_SB_ACCUM(tn, c);
01203           tn->telrcv_state = CURL_TS_SB;
01204         }
01205         else
01206         {
01207           CURL_SB_ACCUM(tn, CURL_IAC);
01208           CURL_SB_ACCUM(tn, CURL_SE);
01209           tn->subpointer -= 2;
01210           CURL_SB_TERM(tn);
01211           suboption(conn);   /* handle sub-option */
01212           tn->telrcv_state = CURL_TS_DATA;
01213         }
01214         break;
01215     }
01216     ++in;
01217   }
01218   bufferflush();
01219   return CURLE_OK;
01220 }
01221 
01222 /* Escape and send a telnet data block */
01223 /* TODO: write large chunks of data instead of one byte at a time */
01224 static CURLcode send_telnet_data(struct connectdata *conn,
01225                                  char *buffer, ssize_t nread)
01226 {
01227   unsigned char outbuf[2];
01228   ssize_t bytes_written, total_written;
01229   int out_count;
01230   CURLcode result = CURLE_OK;
01231 
01232   while(!result && nread--) {
01233     outbuf[0] = *buffer++;
01234     out_count = 1;
01235     if(outbuf[0] == CURL_IAC)
01236       outbuf[out_count++] = CURL_IAC;
01237 
01238     total_written = 0;
01239     do {
01240       /* Make sure socket is writable to avoid EWOULDBLOCK condition */
01241       struct pollfd pfd[1];
01242       pfd[0].fd = conn->sock[FIRSTSOCKET];
01243       pfd[0].events = POLLOUT;
01244       switch(Curl_poll(pfd, 1, -1)) {
01245         case -1:                    /* error, abort writing */
01246         case 0:                     /* timeout (will never happen) */
01247           result = CURLE_SEND_ERROR;
01248           break;
01249         default:                    /* write! */
01250           bytes_written = 0;
01251           result = Curl_write(conn, conn->sock[FIRSTSOCKET],
01252                               outbuf+total_written, out_count-total_written,
01253                               &bytes_written);
01254           total_written += bytes_written;
01255           break;
01256       }
01257       /* handle partial write */
01258     } while(!result && total_written < out_count);
01259   }
01260   return result;
01261 }
01262 
01263 static CURLcode telnet_done(struct connectdata *conn,
01264                                  CURLcode status, bool premature)
01265 {
01266   struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
01267   (void)status; /* unused */
01268   (void)premature; /* not used */
01269 
01270   if(!tn)
01271     return CURLE_OK;
01272 
01273   curl_slist_free_all(tn->telnet_vars);
01274   tn->telnet_vars = NULL;
01275 
01276   Curl_safefree(conn->data->req.protop);
01277 
01278   return CURLE_OK;
01279 }
01280 
01281 static CURLcode telnet_do(struct connectdata *conn, bool *done)
01282 {
01283   CURLcode result;
01284   struct Curl_easy *data = conn->data;
01285   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
01286 #ifdef USE_WINSOCK
01287   HMODULE wsock2;
01288   WSOCK2_FUNC close_event_func;
01289   WSOCK2_FUNC create_event_func;
01290   WSOCK2_FUNC event_select_func;
01291   WSOCK2_FUNC enum_netevents_func;
01292   WSAEVENT event_handle;
01293   WSANETWORKEVENTS events;
01294   HANDLE stdin_handle;
01295   HANDLE objs[2];
01296   DWORD  obj_count;
01297   DWORD  wait_timeout;
01298   DWORD waitret;
01299   DWORD readfile_read;
01300   int err;
01301 #else
01302   int interval_ms;
01303   struct pollfd pfd[2];
01304   int poll_cnt;
01305   curl_off_t total_dl = 0;
01306   curl_off_t total_ul = 0;
01307 #endif
01308   ssize_t nread;
01309   struct timeval now;
01310   bool keepon = TRUE;
01311   char *buf = data->state.buffer;
01312   struct TELNET *tn;
01313 
01314   *done = TRUE; /* unconditionally */
01315 
01316   result = init_telnet(conn);
01317   if(result)
01318     return result;
01319 
01320   tn = (struct TELNET *)data->req.protop;
01321 
01322   result = check_telnet_options(conn);
01323   if(result)
01324     return result;
01325 
01326 #ifdef USE_WINSOCK
01327   /*
01328   ** This functionality only works with WinSock >= 2.0.  So,
01329   ** make sure have it.
01330   */
01331   result = check_wsock2(data);
01332   if(result)
01333     return result;
01334 
01335   /* OK, so we have WinSock 2.0.  We need to dynamically */
01336   /* load ws2_32.dll and get the function pointers we need. */
01337   wsock2 = Curl_load_library(TEXT("WS2_32.DLL"));
01338   if(wsock2 == NULL) {
01339     failf(data, "failed to load WS2_32.DLL (%d)", ERRNO);
01340     return CURLE_FAILED_INIT;
01341   }
01342 
01343   /* Grab a pointer to WSACreateEvent */
01344   create_event_func = GetProcAddress(wsock2, "WSACreateEvent");
01345   if(create_event_func == NULL) {
01346     failf(data, "failed to find WSACreateEvent function (%d)", ERRNO);
01347     FreeLibrary(wsock2);
01348     return CURLE_FAILED_INIT;
01349   }
01350 
01351   /* And WSACloseEvent */
01352   close_event_func = GetProcAddress(wsock2, "WSACloseEvent");
01353   if(close_event_func == NULL) {
01354     failf(data, "failed to find WSACloseEvent function (%d)", ERRNO);
01355     FreeLibrary(wsock2);
01356     return CURLE_FAILED_INIT;
01357   }
01358 
01359   /* And WSAEventSelect */
01360   event_select_func = GetProcAddress(wsock2, "WSAEventSelect");
01361   if(event_select_func == NULL) {
01362     failf(data, "failed to find WSAEventSelect function (%d)", ERRNO);
01363     FreeLibrary(wsock2);
01364     return CURLE_FAILED_INIT;
01365   }
01366 
01367   /* And WSAEnumNetworkEvents */
01368   enum_netevents_func = GetProcAddress(wsock2, "WSAEnumNetworkEvents");
01369   if(enum_netevents_func == NULL) {
01370     failf(data, "failed to find WSAEnumNetworkEvents function (%d)", ERRNO);
01371     FreeLibrary(wsock2);
01372     return CURLE_FAILED_INIT;
01373   }
01374 
01375   /* We want to wait for both stdin and the socket. Since
01376   ** the select() function in winsock only works on sockets
01377   ** we have to use the WaitForMultipleObjects() call.
01378   */
01379 
01380   /* First, create a sockets event object */
01381   event_handle = (WSAEVENT)create_event_func();
01382   if(event_handle == WSA_INVALID_EVENT) {
01383     failf(data, "WSACreateEvent failed (%d)", SOCKERRNO);
01384     FreeLibrary(wsock2);
01385     return CURLE_FAILED_INIT;
01386   }
01387 
01388   /* Tell winsock what events we want to listen to */
01389   if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) ==
01390      SOCKET_ERROR) {
01391     close_event_func(event_handle);
01392     FreeLibrary(wsock2);
01393     return CURLE_OK;
01394   }
01395 
01396   /* The get the Windows file handle for stdin */
01397   stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
01398 
01399   /* Create the list of objects to wait for */
01400   objs[0] = event_handle;
01401   objs[1] = stdin_handle;
01402 
01403   /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
01404      else use the old WaitForMultipleObjects() way */
01405   if(GetFileType(stdin_handle) == FILE_TYPE_PIPE ||
01406      data->set.is_fread_set) {
01407     /* Don't wait for stdin_handle, just wait for event_handle */
01408     obj_count = 1;
01409     /* Check stdin_handle per 100 milliseconds */
01410     wait_timeout = 100;
01411   }
01412   else {
01413     obj_count = 2;
01414     wait_timeout = 1000;
01415   }
01416 
01417   /* Keep on listening and act on events */
01418   while(keepon) {
01419     waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout);
01420     switch(waitret) {
01421     case WAIT_TIMEOUT:
01422     {
01423       for(;;) {
01424         if(data->set.is_fread_set) {
01425           /* read from user-supplied method */
01426           result = (int)data->state.fread_func(buf, 1, BUFSIZE - 1,
01427                                                data->state.in);
01428           if(result == CURL_READFUNC_ABORT) {
01429             keepon = FALSE;
01430             result = CURLE_READ_ERROR;
01431             break;
01432           }
01433 
01434           if(result == CURL_READFUNC_PAUSE)
01435             break;
01436 
01437           if(result == 0)                        /* no bytes */
01438             break;
01439 
01440           readfile_read = result; /* fall thru with number of bytes read */
01441         }
01442         else {
01443           /* read from stdin */
01444           if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL,
01445                             &readfile_read, NULL)) {
01446             keepon = FALSE;
01447             result = CURLE_READ_ERROR;
01448             break;
01449           }
01450 
01451           if(!readfile_read)
01452             break;
01453 
01454           if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
01455                        &readfile_read, NULL)) {
01456             keepon = FALSE;
01457             result = CURLE_READ_ERROR;
01458             break;
01459           }
01460         }
01461 
01462         result = send_telnet_data(conn, buf, readfile_read);
01463         if(result) {
01464           keepon = FALSE;
01465           break;
01466         }
01467       }
01468     }
01469     break;
01470 
01471     case WAIT_OBJECT_0 + 1:
01472     {
01473       if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
01474                    &readfile_read, NULL)) {
01475         keepon = FALSE;
01476         result = CURLE_READ_ERROR;
01477         break;
01478       }
01479 
01480       result = send_telnet_data(conn, buf, readfile_read);
01481       if(result) {
01482         keepon = FALSE;
01483         break;
01484       }
01485     }
01486     break;
01487 
01488     case WAIT_OBJECT_0:
01489 
01490       events.lNetworkEvents = 0;
01491       if(SOCKET_ERROR == enum_netevents_func(sockfd, event_handle, &events)) {
01492         err = SOCKERRNO;
01493         if(err != EINPROGRESS) {
01494           infof(data, "WSAEnumNetworkEvents failed (%d)", err);
01495           keepon = FALSE;
01496           result = CURLE_READ_ERROR;
01497         }
01498         break;
01499       }
01500       if(events.lNetworkEvents & FD_READ) {
01501         /* read data from network */
01502         result = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
01503         /* read would've blocked. Loop again */
01504         if(result == CURLE_AGAIN)
01505           break;
01506         /* returned not-zero, this an error */
01507         else if(result) {
01508           keepon = FALSE;
01509           break;
01510         }
01511         /* returned zero but actually received 0 or less here,
01512            the server closed the connection and we bail out */
01513         else if(nread <= 0) {
01514           keepon = FALSE;
01515           break;
01516         }
01517 
01518         result = telrcv(conn, (unsigned char *) buf, nread);
01519         if(result) {
01520           keepon = FALSE;
01521           break;
01522         }
01523 
01524         /* Negotiate if the peer has started negotiating,
01525            otherwise don't. We don't want to speak telnet with
01526            non-telnet servers, like POP or SMTP. */
01527         if(tn->please_negotiate && !tn->already_negotiated) {
01528           negotiate(conn);
01529           tn->already_negotiated = 1;
01530         }
01531       }
01532       if(events.lNetworkEvents & FD_CLOSE) {
01533         keepon = FALSE;
01534       }
01535       break;
01536 
01537     }
01538 
01539     if(data->set.timeout) {
01540       now = Curl_tvnow();
01541       if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
01542         failf(data, "Time-out");
01543         result = CURLE_OPERATION_TIMEDOUT;
01544         keepon = FALSE;
01545       }
01546     }
01547   }
01548 
01549   /* We called WSACreateEvent, so call WSACloseEvent */
01550   if(!close_event_func(event_handle)) {
01551     infof(data, "WSACloseEvent failed (%d)", SOCKERRNO);
01552   }
01553 
01554   /* "Forget" pointers into the library we're about to free */
01555   create_event_func = NULL;
01556   close_event_func = NULL;
01557   event_select_func = NULL;
01558   enum_netevents_func = NULL;
01559 
01560   /* We called LoadLibrary, so call FreeLibrary */
01561   if(!FreeLibrary(wsock2))
01562     infof(data, "FreeLibrary(wsock2) failed (%d)", ERRNO);
01563 #else
01564   pfd[0].fd = sockfd;
01565   pfd[0].events = POLLIN;
01566 
01567   if(data->set.is_fread_set) {
01568     poll_cnt = 1;
01569     interval_ms = 100; /* poll user-supplied read function */
01570   }
01571   else {
01572     /* really using fread, so infile is a FILE* */
01573     pfd[1].fd = fileno((FILE *)data->state.in);
01574     pfd[1].events = POLLIN;
01575     poll_cnt = 2;
01576     interval_ms = 1 * 1000;
01577   }
01578 
01579   while(keepon) {
01580     switch(Curl_poll(pfd, poll_cnt, interval_ms)) {
01581     case -1:                    /* error, stop reading */
01582       keepon = FALSE;
01583       continue;
01584     case 0:                     /* timeout */
01585       pfd[0].revents = 0;
01586       pfd[1].revents = 0;
01587       /* fall through */
01588     default:                    /* read! */
01589       if(pfd[0].revents & POLLIN) {
01590         /* read data from network */
01591         result = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
01592         /* read would've blocked. Loop again */
01593         if(result == CURLE_AGAIN)
01594           break;
01595         /* returned not-zero, this an error */
01596         else if(result) {
01597           keepon = FALSE;
01598           break;
01599         }
01600         /* returned zero but actually received 0 or less here,
01601            the server closed the connection and we bail out */
01602         else if(nread <= 0) {
01603           keepon = FALSE;
01604           break;
01605         }
01606 
01607         total_dl += nread;
01608         Curl_pgrsSetDownloadCounter(data, total_dl);
01609         result = telrcv(conn, (unsigned char *)buf, nread);
01610         if(result) {
01611           keepon = FALSE;
01612           break;
01613         }
01614 
01615         /* Negotiate if the peer has started negotiating,
01616            otherwise don't. We don't want to speak telnet with
01617            non-telnet servers, like POP or SMTP. */
01618         if(tn->please_negotiate && !tn->already_negotiated) {
01619           negotiate(conn);
01620           tn->already_negotiated = 1;
01621         }
01622       }
01623 
01624       nread = 0;
01625       if(poll_cnt == 2) {
01626         if(pfd[1].revents & POLLIN) { /* read from in file */
01627           nread = read(pfd[1].fd, buf, BUFSIZE - 1);
01628         }
01629       }
01630       else {
01631         /* read from user-supplied method */
01632         nread = (int)data->state.fread_func(buf, 1, BUFSIZE - 1,
01633                                             data->state.in);
01634         if(nread == CURL_READFUNC_ABORT) {
01635           keepon = FALSE;
01636           break;
01637         }
01638         if(nread == CURL_READFUNC_PAUSE)
01639           break;
01640       }
01641 
01642       if(nread > 0) {
01643         result = send_telnet_data(conn, buf, nread);
01644         if(result) {
01645           keepon = FALSE;
01646           break;
01647         }
01648         total_ul += nread;
01649         Curl_pgrsSetUploadCounter(data, total_ul);
01650       }
01651       else if(nread < 0)
01652         keepon = FALSE;
01653 
01654       break;
01655     } /* poll switch statement */
01656 
01657     if(data->set.timeout) {
01658       now = Curl_tvnow();
01659       if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
01660         failf(data, "Time-out");
01661         result = CURLE_OPERATION_TIMEDOUT;
01662         keepon = FALSE;
01663       }
01664     }
01665 
01666     if(Curl_pgrsUpdate(conn)) {
01667       result = CURLE_ABORTED_BY_CALLBACK;
01668       break;
01669     }
01670   }
01671 #endif
01672   /* mark this as "no further transfer wanted" */
01673   Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
01674 
01675   return result;
01676 }
01677 #endif


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:06