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