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