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