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
str_is_nonascii(const char * str)771 static bool str_is_nonascii(const char *str)
772 {
773 size_t len = strlen(str);
774 while(len--) {
775 if(*str & 0x80)
776 return TRUE;
777 str++;
778 }
779 return FALSE;
780 }
781
check_telnet_options(struct Curl_easy * data)782 static CURLcode check_telnet_options(struct Curl_easy *data)
783 {
784 struct curl_slist *head;
785 struct curl_slist *beg;
786 char option_keyword[128] = "";
787 char option_arg[256] = "";
788 struct TELNET *tn = data->req.p.telnet;
789 struct connectdata *conn = data->conn;
790 CURLcode result = CURLE_OK;
791 int binary_option;
792
793 /* Add the user name as an environment variable if it
794 was given on the command line */
795 if(conn->bits.user_passwd) {
796 if(str_is_nonascii(conn->user))
797 return CURLE_BAD_FUNCTION_ARGUMENT;
798 msnprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
799 beg = curl_slist_append(tn->telnet_vars, option_arg);
800 if(!beg) {
801 curl_slist_free_all(tn->telnet_vars);
802 tn->telnet_vars = NULL;
803 return CURLE_OUT_OF_MEMORY;
804 }
805 tn->telnet_vars = beg;
806 tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
807 }
808
809 for(head = data->set.telnet_options; head; head = head->next) {
810 if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
811 option_keyword, option_arg) == 2) {
812
813 if(str_is_nonascii(option_arg))
814 continue;
815
816 /* Terminal type */
817 if(strcasecompare(option_keyword, "TTYPE")) {
818 strncpy(tn->subopt_ttype, option_arg, 31);
819 tn->subopt_ttype[31] = 0; /* String termination */
820 tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
821 continue;
822 }
823
824 /* Display variable */
825 if(strcasecompare(option_keyword, "XDISPLOC")) {
826 strncpy(tn->subopt_xdisploc, option_arg, 127);
827 tn->subopt_xdisploc[127] = 0; /* String termination */
828 tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
829 continue;
830 }
831
832 /* Environment variable */
833 if(strcasecompare(option_keyword, "NEW_ENV")) {
834 beg = curl_slist_append(tn->telnet_vars, option_arg);
835 if(!beg) {
836 result = CURLE_OUT_OF_MEMORY;
837 break;
838 }
839 tn->telnet_vars = beg;
840 tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
841 continue;
842 }
843
844 /* Window Size */
845 if(strcasecompare(option_keyword, "WS")) {
846 if(sscanf(option_arg, "%hu%*[xX]%hu",
847 &tn->subopt_wsx, &tn->subopt_wsy) == 2)
848 tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
849 else {
850 failf(data, "Syntax error in telnet option: %s", head->data);
851 result = CURLE_SETOPT_OPTION_SYNTAX;
852 break;
853 }
854 continue;
855 }
856
857 /* To take care or not of the 8th bit in data exchange */
858 if(strcasecompare(option_keyword, "BINARY")) {
859 binary_option = atoi(option_arg);
860 if(binary_option != 1) {
861 tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO;
862 tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO;
863 }
864 continue;
865 }
866
867 failf(data, "Unknown telnet option %s", head->data);
868 result = CURLE_UNKNOWN_OPTION;
869 break;
870 }
871 failf(data, "Syntax error in telnet option: %s", head->data);
872 result = CURLE_SETOPT_OPTION_SYNTAX;
873 break;
874 }
875
876 if(result) {
877 curl_slist_free_all(tn->telnet_vars);
878 tn->telnet_vars = NULL;
879 }
880
881 return result;
882 }
883
884 /*
885 * suboption()
886 *
887 * Look at the sub-option buffer, and try to be helpful to the other
888 * side.
889 */
890
suboption(struct Curl_easy * data)891 static void suboption(struct Curl_easy *data)
892 {
893 struct curl_slist *v;
894 unsigned char temp[2048];
895 ssize_t bytes_written;
896 size_t len;
897 int err;
898 char varname[128] = "";
899 char varval[128] = "";
900 struct TELNET *tn = data->req.p.telnet;
901 struct connectdata *conn = data->conn;
902
903 printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn) + 2);
904 switch(CURL_SB_GET(tn)) {
905 case CURL_TELOPT_TTYPE:
906 len = strlen(tn->subopt_ttype) + 4 + 2;
907 msnprintf((char *)temp, sizeof(temp),
908 "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
909 CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE);
910 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
911 if(bytes_written < 0) {
912 err = SOCKERRNO;
913 failf(data,"Sending data failed (%d)",err);
914 }
915 printsub(data, '>', &temp[2], len-2);
916 break;
917 case CURL_TELOPT_XDISPLOC:
918 len = strlen(tn->subopt_xdisploc) + 4 + 2;
919 msnprintf((char *)temp, sizeof(temp),
920 "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
921 CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE);
922 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
923 if(bytes_written < 0) {
924 err = SOCKERRNO;
925 failf(data,"Sending data failed (%d)",err);
926 }
927 printsub(data, '>', &temp[2], len-2);
928 break;
929 case CURL_TELOPT_NEW_ENVIRON:
930 msnprintf((char *)temp, sizeof(temp),
931 "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON,
932 CURL_TELQUAL_IS);
933 len = 4;
934
935 for(v = tn->telnet_vars; v; v = v->next) {
936 size_t tmplen = (strlen(v->data) + 1);
937 /* Add the variable only if it fits */
938 if(len + tmplen < (int)sizeof(temp)-6) {
939 int rv;
940 char sep[2] = "";
941 varval[0] = 0;
942 rv = sscanf(v->data, "%127[^,]%1[,]%127s", varname, sep, varval);
943 if(rv == 1)
944 len += msnprintf((char *)&temp[len], sizeof(temp) - len,
945 "%c%s", CURL_NEW_ENV_VAR, varname);
946 else if(rv >= 2)
947 len += msnprintf((char *)&temp[len], sizeof(temp) - len,
948 "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
949 CURL_NEW_ENV_VALUE, varval);
950 }
951 }
952 msnprintf((char *)&temp[len], sizeof(temp) - len,
953 "%c%c", CURL_IAC, CURL_SE);
954 len += 2;
955 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
956 if(bytes_written < 0) {
957 err = SOCKERRNO;
958 failf(data,"Sending data failed (%d)",err);
959 }
960 printsub(data, '>', &temp[2], len-2);
961 break;
962 }
963 return;
964 }
965
966
967 /*
968 * sendsuboption()
969 *
970 * Send suboption information to the server side.
971 */
972
sendsuboption(struct Curl_easy * data,int option)973 static void sendsuboption(struct Curl_easy *data, int option)
974 {
975 ssize_t bytes_written;
976 int err;
977 unsigned short x, y;
978 unsigned char *uc1, *uc2;
979 struct TELNET *tn = data->req.p.telnet;
980 struct connectdata *conn = data->conn;
981
982 switch(option) {
983 case CURL_TELOPT_NAWS:
984 /* We prepare data to be sent */
985 CURL_SB_CLEAR(tn);
986 CURL_SB_ACCUM(tn, CURL_IAC);
987 CURL_SB_ACCUM(tn, CURL_SB);
988 CURL_SB_ACCUM(tn, CURL_TELOPT_NAWS);
989 /* We must deal either with little or big endian processors */
990 /* Window size must be sent according to the 'network order' */
991 x = htons(tn->subopt_wsx);
992 y = htons(tn->subopt_wsy);
993 uc1 = (unsigned char *)&x;
994 uc2 = (unsigned char *)&y;
995 CURL_SB_ACCUM(tn, uc1[0]);
996 CURL_SB_ACCUM(tn, uc1[1]);
997 CURL_SB_ACCUM(tn, uc2[0]);
998 CURL_SB_ACCUM(tn, uc2[1]);
999
1000 CURL_SB_ACCUM(tn, CURL_IAC);
1001 CURL_SB_ACCUM(tn, CURL_SE);
1002 CURL_SB_TERM(tn);
1003 /* data suboption is now ready */
1004
1005 printsub(data, '>', (unsigned char *)tn->subbuffer + 2,
1006 CURL_SB_LEN(tn)-2);
1007
1008 /* we send the header of the suboption... */
1009 bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer, 3);
1010 if(bytes_written < 0) {
1011 err = SOCKERRNO;
1012 failf(data, "Sending data failed (%d)", err);
1013 }
1014 /* ... then the window size with the send_telnet_data() function
1015 to deal with 0xFF cases ... */
1016 send_telnet_data(data, (char *)tn->subbuffer + 3, 4);
1017 /* ... and the footer */
1018 bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer + 7, 2);
1019 if(bytes_written < 0) {
1020 err = SOCKERRNO;
1021 failf(data, "Sending data failed (%d)", err);
1022 }
1023 break;
1024 }
1025 }
1026
1027
1028 static
telrcv(struct Curl_easy * data,const unsigned char * inbuf,ssize_t count)1029 CURLcode telrcv(struct Curl_easy *data,
1030 const unsigned char *inbuf, /* Data received from socket */
1031 ssize_t count) /* Number of bytes received */
1032 {
1033 unsigned char c;
1034 CURLcode result;
1035 int in = 0;
1036 int startwrite = -1;
1037 struct TELNET *tn = data->req.p.telnet;
1038
1039 #define startskipping() \
1040 if(startwrite >= 0) { \
1041 result = Curl_client_write(data, \
1042 CLIENTWRITE_BODY, \
1043 (char *)&inbuf[startwrite], \
1044 in-startwrite); \
1045 if(result) \
1046 return result; \
1047 } \
1048 startwrite = -1
1049
1050 #define writebyte() \
1051 if(startwrite < 0) \
1052 startwrite = in
1053
1054 #define bufferflush() startskipping()
1055
1056 while(count--) {
1057 c = inbuf[in];
1058
1059 switch(tn->telrcv_state) {
1060 case CURL_TS_CR:
1061 tn->telrcv_state = CURL_TS_DATA;
1062 if(c == '\0') {
1063 startskipping();
1064 break; /* Ignore \0 after CR */
1065 }
1066 writebyte();
1067 break;
1068
1069 case CURL_TS_DATA:
1070 if(c == CURL_IAC) {
1071 tn->telrcv_state = CURL_TS_IAC;
1072 startskipping();
1073 break;
1074 }
1075 else if(c == '\r')
1076 tn->telrcv_state = CURL_TS_CR;
1077 writebyte();
1078 break;
1079
1080 case CURL_TS_IAC:
1081 process_iac:
1082 DEBUGASSERT(startwrite < 0);
1083 switch(c) {
1084 case CURL_WILL:
1085 tn->telrcv_state = CURL_TS_WILL;
1086 break;
1087 case CURL_WONT:
1088 tn->telrcv_state = CURL_TS_WONT;
1089 break;
1090 case CURL_DO:
1091 tn->telrcv_state = CURL_TS_DO;
1092 break;
1093 case CURL_DONT:
1094 tn->telrcv_state = CURL_TS_DONT;
1095 break;
1096 case CURL_SB:
1097 CURL_SB_CLEAR(tn);
1098 tn->telrcv_state = CURL_TS_SB;
1099 break;
1100 case CURL_IAC:
1101 tn->telrcv_state = CURL_TS_DATA;
1102 writebyte();
1103 break;
1104 case CURL_DM:
1105 case CURL_NOP:
1106 case CURL_GA:
1107 default:
1108 tn->telrcv_state = CURL_TS_DATA;
1109 printoption(data, "RCVD", CURL_IAC, c);
1110 break;
1111 }
1112 break;
1113
1114 case CURL_TS_WILL:
1115 printoption(data, "RCVD", CURL_WILL, c);
1116 tn->please_negotiate = 1;
1117 rec_will(data, c);
1118 tn->telrcv_state = CURL_TS_DATA;
1119 break;
1120
1121 case CURL_TS_WONT:
1122 printoption(data, "RCVD", CURL_WONT, c);
1123 tn->please_negotiate = 1;
1124 rec_wont(data, c);
1125 tn->telrcv_state = CURL_TS_DATA;
1126 break;
1127
1128 case CURL_TS_DO:
1129 printoption(data, "RCVD", CURL_DO, c);
1130 tn->please_negotiate = 1;
1131 rec_do(data, c);
1132 tn->telrcv_state = CURL_TS_DATA;
1133 break;
1134
1135 case CURL_TS_DONT:
1136 printoption(data, "RCVD", CURL_DONT, c);
1137 tn->please_negotiate = 1;
1138 rec_dont(data, c);
1139 tn->telrcv_state = CURL_TS_DATA;
1140 break;
1141
1142 case CURL_TS_SB:
1143 if(c == CURL_IAC)
1144 tn->telrcv_state = CURL_TS_SE;
1145 else
1146 CURL_SB_ACCUM(tn, c);
1147 break;
1148
1149 case CURL_TS_SE:
1150 if(c != CURL_SE) {
1151 if(c != CURL_IAC) {
1152 /*
1153 * This is an error. We only expect to get "IAC IAC" or "IAC SE".
1154 * Several things may have happened. An IAC was not doubled, the
1155 * IAC SE was left off, or another option got inserted into the
1156 * suboption are all possibilities. If we assume that the IAC was
1157 * not doubled, and really the IAC SE was left off, we could get
1158 * into an infinite loop here. So, instead, we terminate the
1159 * suboption, and process the partial suboption if we can.
1160 */
1161 CURL_SB_ACCUM(tn, CURL_IAC);
1162 CURL_SB_ACCUM(tn, c);
1163 tn->subpointer -= 2;
1164 CURL_SB_TERM(tn);
1165
1166 printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c);
1167 suboption(data); /* handle sub-option */
1168 tn->telrcv_state = CURL_TS_IAC;
1169 goto process_iac;
1170 }
1171 CURL_SB_ACCUM(tn, c);
1172 tn->telrcv_state = CURL_TS_SB;
1173 }
1174 else {
1175 CURL_SB_ACCUM(tn, CURL_IAC);
1176 CURL_SB_ACCUM(tn, CURL_SE);
1177 tn->subpointer -= 2;
1178 CURL_SB_TERM(tn);
1179 suboption(data); /* handle sub-option */
1180 tn->telrcv_state = CURL_TS_DATA;
1181 }
1182 break;
1183 }
1184 ++in;
1185 }
1186 bufferflush();
1187 return CURLE_OK;
1188 }
1189
1190 /* Escape and send a telnet data block */
send_telnet_data(struct Curl_easy * data,char * buffer,ssize_t nread)1191 static CURLcode send_telnet_data(struct Curl_easy *data,
1192 char *buffer, ssize_t nread)
1193 {
1194 ssize_t escapes, i, outlen;
1195 unsigned char *outbuf = NULL;
1196 CURLcode result = CURLE_OK;
1197 ssize_t bytes_written, total_written;
1198 struct connectdata *conn = data->conn;
1199
1200 /* Determine size of new buffer after escaping */
1201 escapes = 0;
1202 for(i = 0; i < nread; i++)
1203 if((unsigned char)buffer[i] == CURL_IAC)
1204 escapes++;
1205 outlen = nread + escapes;
1206
1207 if(outlen == nread)
1208 outbuf = (unsigned char *)buffer;
1209 else {
1210 ssize_t j;
1211 outbuf = malloc(nread + escapes + 1);
1212 if(!outbuf)
1213 return CURLE_OUT_OF_MEMORY;
1214
1215 j = 0;
1216 for(i = 0; i < nread; i++) {
1217 outbuf[j++] = buffer[i];
1218 if((unsigned char)buffer[i] == CURL_IAC)
1219 outbuf[j++] = CURL_IAC;
1220 }
1221 outbuf[j] = '\0';
1222 }
1223
1224 total_written = 0;
1225 while(!result && total_written < outlen) {
1226 /* Make sure socket is writable to avoid EWOULDBLOCK condition */
1227 struct pollfd pfd[1];
1228 pfd[0].fd = conn->sock[FIRSTSOCKET];
1229 pfd[0].events = POLLOUT;
1230 switch(Curl_poll(pfd, 1, -1)) {
1231 case -1: /* error, abort writing */
1232 case 0: /* timeout (will never happen) */
1233 result = CURLE_SEND_ERROR;
1234 break;
1235 default: /* write! */
1236 bytes_written = 0;
1237 result = Curl_write(data, conn->sock[FIRSTSOCKET],
1238 outbuf + total_written,
1239 outlen - total_written,
1240 &bytes_written);
1241 total_written += bytes_written;
1242 break;
1243 }
1244 }
1245
1246 /* Free malloc copy if escaped */
1247 if(outbuf != (unsigned char *)buffer)
1248 free(outbuf);
1249
1250 return result;
1251 }
1252
telnet_done(struct Curl_easy * data,CURLcode status,bool premature)1253 static CURLcode telnet_done(struct Curl_easy *data,
1254 CURLcode status, bool premature)
1255 {
1256 struct TELNET *tn = data->req.p.telnet;
1257 (void)status; /* unused */
1258 (void)premature; /* not used */
1259
1260 if(!tn)
1261 return CURLE_OK;
1262
1263 curl_slist_free_all(tn->telnet_vars);
1264 tn->telnet_vars = NULL;
1265 return CURLE_OK;
1266 }
1267
telnet_do(struct Curl_easy * data,bool * done)1268 static CURLcode telnet_do(struct Curl_easy *data, bool *done)
1269 {
1270 CURLcode result;
1271 struct connectdata *conn = data->conn;
1272 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
1273 #ifdef USE_WINSOCK
1274 WSAEVENT event_handle;
1275 WSANETWORKEVENTS events;
1276 HANDLE stdin_handle;
1277 HANDLE objs[2];
1278 DWORD obj_count;
1279 DWORD wait_timeout;
1280 DWORD readfile_read;
1281 int err;
1282 #else
1283 timediff_t interval_ms;
1284 struct pollfd pfd[2];
1285 int poll_cnt;
1286 curl_off_t total_dl = 0;
1287 curl_off_t total_ul = 0;
1288 #endif
1289 ssize_t nread;
1290 struct curltime now;
1291 bool keepon = TRUE;
1292 char *buf = data->state.buffer;
1293 struct TELNET *tn;
1294
1295 *done = TRUE; /* unconditionally */
1296
1297 result = init_telnet(data);
1298 if(result)
1299 return result;
1300
1301 tn = data->req.p.telnet;
1302
1303 result = check_telnet_options(data);
1304 if(result)
1305 return result;
1306
1307 #ifdef USE_WINSOCK
1308 /* We want to wait for both stdin and the socket. Since
1309 ** the select() function in winsock only works on sockets
1310 ** we have to use the WaitForMultipleObjects() call.
1311 */
1312
1313 /* First, create a sockets event object */
1314 event_handle = WSACreateEvent();
1315 if(event_handle == WSA_INVALID_EVENT) {
1316 failf(data, "WSACreateEvent failed (%d)", SOCKERRNO);
1317 return CURLE_FAILED_INIT;
1318 }
1319
1320 /* Tell winsock what events we want to listen to */
1321 if(WSAEventSelect(sockfd, event_handle, FD_READ|FD_CLOSE) == SOCKET_ERROR) {
1322 WSACloseEvent(event_handle);
1323 return CURLE_OK;
1324 }
1325
1326 /* The get the Windows file handle for stdin */
1327 stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
1328
1329 /* Create the list of objects to wait for */
1330 objs[0] = event_handle;
1331 objs[1] = stdin_handle;
1332
1333 /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
1334 else use the old WaitForMultipleObjects() way */
1335 if(GetFileType(stdin_handle) == FILE_TYPE_PIPE ||
1336 data->set.is_fread_set) {
1337 /* Don't wait for stdin_handle, just wait for event_handle */
1338 obj_count = 1;
1339 /* Check stdin_handle per 100 milliseconds */
1340 wait_timeout = 100;
1341 }
1342 else {
1343 obj_count = 2;
1344 wait_timeout = 1000;
1345 }
1346
1347 /* Keep on listening and act on events */
1348 while(keepon) {
1349 const DWORD buf_size = (DWORD)data->set.buffer_size;
1350 DWORD waitret = WaitForMultipleObjects(obj_count, objs,
1351 FALSE, wait_timeout);
1352 switch(waitret) {
1353
1354 case WAIT_TIMEOUT:
1355 {
1356 for(;;) {
1357 if(data->set.is_fread_set) {
1358 size_t n;
1359 /* read from user-supplied method */
1360 n = data->state.fread_func(buf, 1, buf_size, data->state.in);
1361 if(n == CURL_READFUNC_ABORT) {
1362 keepon = FALSE;
1363 result = CURLE_READ_ERROR;
1364 break;
1365 }
1366
1367 if(n == CURL_READFUNC_PAUSE)
1368 break;
1369
1370 if(n == 0) /* no bytes */
1371 break;
1372
1373 /* fall through with number of bytes read */
1374 readfile_read = (DWORD)n;
1375 }
1376 else {
1377 /* read from stdin */
1378 if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL,
1379 &readfile_read, NULL)) {
1380 keepon = FALSE;
1381 result = CURLE_READ_ERROR;
1382 break;
1383 }
1384
1385 if(!readfile_read)
1386 break;
1387
1388 if(!ReadFile(stdin_handle, buf, buf_size,
1389 &readfile_read, NULL)) {
1390 keepon = FALSE;
1391 result = CURLE_READ_ERROR;
1392 break;
1393 }
1394 }
1395
1396 result = send_telnet_data(data, buf, readfile_read);
1397 if(result) {
1398 keepon = FALSE;
1399 break;
1400 }
1401 }
1402 }
1403 break;
1404
1405 case WAIT_OBJECT_0 + 1:
1406 {
1407 if(!ReadFile(stdin_handle, buf, buf_size,
1408 &readfile_read, NULL)) {
1409 keepon = FALSE;
1410 result = CURLE_READ_ERROR;
1411 break;
1412 }
1413
1414 result = send_telnet_data(data, buf, readfile_read);
1415 if(result) {
1416 keepon = FALSE;
1417 break;
1418 }
1419 }
1420 break;
1421
1422 case WAIT_OBJECT_0:
1423 {
1424 events.lNetworkEvents = 0;
1425 if(WSAEnumNetworkEvents(sockfd, event_handle, &events) == SOCKET_ERROR) {
1426 err = SOCKERRNO;
1427 if(err != EINPROGRESS) {
1428 infof(data, "WSAEnumNetworkEvents failed (%d)", err);
1429 keepon = FALSE;
1430 result = CURLE_READ_ERROR;
1431 }
1432 break;
1433 }
1434 if(events.lNetworkEvents & FD_READ) {
1435 /* read data from network */
1436 result = Curl_read(data, sockfd, buf, data->set.buffer_size, &nread);
1437 /* read would've blocked. Loop again */
1438 if(result == CURLE_AGAIN)
1439 break;
1440 /* returned not-zero, this an error */
1441 else if(result) {
1442 keepon = FALSE;
1443 break;
1444 }
1445 /* returned zero but actually received 0 or less here,
1446 the server closed the connection and we bail out */
1447 else if(nread <= 0) {
1448 keepon = FALSE;
1449 break;
1450 }
1451
1452 result = telrcv(data, (unsigned char *) buf, nread);
1453 if(result) {
1454 keepon = FALSE;
1455 break;
1456 }
1457
1458 /* Negotiate if the peer has started negotiating,
1459 otherwise don't. We don't want to speak telnet with
1460 non-telnet servers, like POP or SMTP. */
1461 if(tn->please_negotiate && !tn->already_negotiated) {
1462 negotiate(data);
1463 tn->already_negotiated = 1;
1464 }
1465 }
1466 if(events.lNetworkEvents & FD_CLOSE) {
1467 keepon = FALSE;
1468 }
1469 }
1470 break;
1471
1472 }
1473
1474 if(data->set.timeout) {
1475 now = Curl_now();
1476 if(Curl_timediff(now, conn->created) >= data->set.timeout) {
1477 failf(data, "Time-out");
1478 result = CURLE_OPERATION_TIMEDOUT;
1479 keepon = FALSE;
1480 }
1481 }
1482 }
1483
1484 /* We called WSACreateEvent, so call WSACloseEvent */
1485 if(!WSACloseEvent(event_handle)) {
1486 infof(data, "WSACloseEvent failed (%d)", SOCKERRNO);
1487 }
1488 #else
1489 pfd[0].fd = sockfd;
1490 pfd[0].events = POLLIN;
1491
1492 if(data->set.is_fread_set) {
1493 poll_cnt = 1;
1494 interval_ms = 100; /* poll user-supplied read function */
1495 }
1496 else {
1497 /* really using fread, so infile is a FILE* */
1498 pfd[1].fd = fileno((FILE *)data->state.in);
1499 pfd[1].events = POLLIN;
1500 poll_cnt = 2;
1501 interval_ms = 1 * 1000;
1502 }
1503
1504 while(keepon) {
1505 switch(Curl_poll(pfd, poll_cnt, interval_ms)) {
1506 case -1: /* error, stop reading */
1507 keepon = FALSE;
1508 continue;
1509 case 0: /* timeout */
1510 pfd[0].revents = 0;
1511 pfd[1].revents = 0;
1512 /* FALLTHROUGH */
1513 default: /* read! */
1514 if(pfd[0].revents & POLLIN) {
1515 /* read data from network */
1516 result = Curl_read(data, sockfd, buf, data->set.buffer_size, &nread);
1517 /* read would've blocked. Loop again */
1518 if(result == CURLE_AGAIN)
1519 break;
1520 /* returned not-zero, this an error */
1521 if(result) {
1522 keepon = FALSE;
1523 break;
1524 }
1525 /* returned zero but actually received 0 or less here,
1526 the server closed the connection and we bail out */
1527 else if(nread <= 0) {
1528 keepon = FALSE;
1529 break;
1530 }
1531
1532 total_dl += nread;
1533 Curl_pgrsSetDownloadCounter(data, total_dl);
1534 result = telrcv(data, (unsigned char *)buf, nread);
1535 if(result) {
1536 keepon = FALSE;
1537 break;
1538 }
1539
1540 /* Negotiate if the peer has started negotiating,
1541 otherwise don't. We don't want to speak telnet with
1542 non-telnet servers, like POP or SMTP. */
1543 if(tn->please_negotiate && !tn->already_negotiated) {
1544 negotiate(data);
1545 tn->already_negotiated = 1;
1546 }
1547 }
1548
1549 nread = 0;
1550 if(poll_cnt == 2) {
1551 if(pfd[1].revents & POLLIN) { /* read from in file */
1552 nread = read(pfd[1].fd, buf, data->set.buffer_size);
1553 }
1554 }
1555 else {
1556 /* read from user-supplied method */
1557 nread = (int)data->state.fread_func(buf, 1, data->set.buffer_size,
1558 data->state.in);
1559 if(nread == CURL_READFUNC_ABORT) {
1560 keepon = FALSE;
1561 break;
1562 }
1563 if(nread == CURL_READFUNC_PAUSE)
1564 break;
1565 }
1566
1567 if(nread > 0) {
1568 result = send_telnet_data(data, buf, nread);
1569 if(result) {
1570 keepon = FALSE;
1571 break;
1572 }
1573 total_ul += nread;
1574 Curl_pgrsSetUploadCounter(data, total_ul);
1575 }
1576 else if(nread < 0)
1577 keepon = FALSE;
1578
1579 break;
1580 } /* poll switch statement */
1581
1582 if(data->set.timeout) {
1583 now = Curl_now();
1584 if(Curl_timediff(now, conn->created) >= data->set.timeout) {
1585 failf(data, "Time-out");
1586 result = CURLE_OPERATION_TIMEDOUT;
1587 keepon = FALSE;
1588 }
1589 }
1590
1591 if(Curl_pgrsUpdate(data)) {
1592 result = CURLE_ABORTED_BY_CALLBACK;
1593 break;
1594 }
1595 }
1596 #endif
1597 /* mark this as "no further transfer wanted" */
1598 Curl_setup_transfer(data, -1, -1, FALSE, -1);
1599
1600 return result;
1601 }
1602 #endif
1603