1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2020, 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.haxx.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 connectdata *,
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 connectdata *);
102 static void send_negotiation(struct connectdata *, int cmd, int option);
103 static void set_local_option(struct connectdata *conn,
104 int option, int newstate);
105 static void set_remote_option(struct connectdata *conn,
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 connectdata *);
112 static void sendsuboption(struct connectdata *conn, int option);
113
114 static CURLcode telnet_do(struct connectdata *conn, bool *done);
115 static CURLcode telnet_done(struct connectdata *conn,
116 CURLcode, bool premature);
117 static CURLcode send_telnet_data(struct connectdata *conn,
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 struct curl_slist *telnet_vars; /* Environment variables */
160
161 /* suboptions */
162 unsigned char subbuffer[SUBBUFSIZE];
163 unsigned char *subpointer, *subend; /* buffer for sub-options */
164
165 TelnetReceive telrcv_state;
166 };
167
168
169 /*
170 * TELNET protocol handler.
171 */
172
173 const struct Curl_handler Curl_handler_telnet = {
174 "TELNET", /* scheme */
175 ZERO_NULL, /* setup_connection */
176 telnet_do, /* do_it */
177 telnet_done, /* done */
178 ZERO_NULL, /* do_more */
179 ZERO_NULL, /* connect_it */
180 ZERO_NULL, /* connecting */
181 ZERO_NULL, /* doing */
182 ZERO_NULL, /* proto_getsock */
183 ZERO_NULL, /* doing_getsock */
184 ZERO_NULL, /* domore_getsock */
185 ZERO_NULL, /* perform_getsock */
186 ZERO_NULL, /* disconnect */
187 ZERO_NULL, /* readwrite */
188 ZERO_NULL, /* connection_check */
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 connectdata * conn)197 CURLcode init_telnet(struct connectdata *conn)
198 {
199 struct TELNET *tn;
200
201 tn = calloc(1, sizeof(struct TELNET));
202 if(!tn)
203 return CURLE_OUT_OF_MEMORY;
204
205 conn->data->req.protop = 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 behaviour
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 connectdata * conn)247 static void negotiate(struct connectdata *conn)
248 {
249 int i;
250 struct TELNET *tn = (struct TELNET *) conn->data->req.protop;
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(conn, i, CURL_YES);
258
259 if(tn->him_preferred[i] == CURL_YES)
260 set_remote_option(conn, 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\n", direction, CURL_TELCMD(option));
272 else
273 infof(data, "%s IAC %d\n", 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\n", direction, fmt, opt);
291 else
292 infof(data, "%s %s %d\n", direction, fmt, option);
293 }
294 else
295 infof(data, "%s %d %d\n", direction, cmd, option);
296 }
297 }
298 }
299 #endif
300
send_negotiation(struct connectdata * conn,int cmd,int option)301 static void send_negotiation(struct connectdata *conn, int cmd, int option)
302 {
303 unsigned char buf[3];
304 ssize_t bytes_written;
305 struct Curl_easy *data = conn->data;
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(conn->data, "SENT", cmd, option);
318 }
319
320 static
set_remote_option(struct connectdata * conn,int option,int newstate)321 void set_remote_option(struct connectdata *conn, int option, int newstate)
322 {
323 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
324 if(newstate == CURL_YES) {
325 switch(tn->him[option]) {
326 case CURL_NO:
327 tn->him[option] = CURL_WANTYES;
328 send_negotiation(conn, 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(conn, 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 connectdata * conn,int option)395 void rec_will(struct connectdata *conn, int option)
396 {
397 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
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(conn, CURL_DO, option);
403 }
404 else
405 send_negotiation(conn, 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(conn, CURL_DONT, option);
436 break;
437 }
438 break;
439 }
440 }
441
442 static
rec_wont(struct connectdata * conn,int option)443 void rec_wont(struct connectdata *conn, int option)
444 {
445 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
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(conn, 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(conn, 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 connectdata * conn,int option,int newstate)485 set_local_option(struct connectdata *conn, int option, int newstate)
486 {
487 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
488 if(newstate == CURL_YES) {
489 switch(tn->us[option]) {
490 case CURL_NO:
491 tn->us[option] = CURL_WANTYES;
492 send_negotiation(conn, 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(conn, 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 connectdata * conn,int option)559 void rec_do(struct connectdata *conn, int option)
560 {
561 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
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(conn, CURL_WILL, option);
567 if(tn->subnegotiation[option] == CURL_YES)
568 /* transmission of data option */
569 sendsuboption(conn, 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(conn, CURL_WILL, option);
575 sendsuboption(conn, option);
576 }
577 else
578 send_negotiation(conn, 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(conn, option);
606 }
607 break;
608 case CURL_OPPOSITE:
609 tn->us[option] = CURL_WANTNO;
610 tn->himq[option] = CURL_EMPTY;
611 send_negotiation(conn, CURL_WONT, option);
612 break;
613 }
614 break;
615 }
616 }
617
618 static
rec_dont(struct connectdata * conn,int option)619 void rec_dont(struct connectdata *conn, int option)
620 {
621 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
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(conn, 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(conn, 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 if(direction)
769 infof(data, "\n");
770 }
771 }
772
check_telnet_options(struct connectdata * conn)773 static CURLcode check_telnet_options(struct connectdata *conn)
774 {
775 struct curl_slist *head;
776 struct curl_slist *beg;
777 char option_keyword[128] = "";
778 char option_arg[256] = "";
779 struct Curl_easy *data = conn->data;
780 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
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(conn->bits.user_passwd) {
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_TELNET_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_TELNET_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
suboption(struct connectdata * conn)877 static void suboption(struct connectdata *conn)
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 Curl_easy *data = conn->data;
887 struct TELNET *tn = (struct TELNET *)data->req.protop;
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 if(sscanf(v->data, "%127[^,],%127s", varname, varval)) {
926 msnprintf((char *)&temp[len], sizeof(temp) - len,
927 "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
928 CURL_NEW_ENV_VALUE, varval);
929 len += tmplen;
930 }
931 }
932 }
933 msnprintf((char *)&temp[len], sizeof(temp) - len,
934 "%c%c", CURL_IAC, CURL_SE);
935 len += 2;
936 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
937 if(bytes_written < 0) {
938 err = SOCKERRNO;
939 failf(data,"Sending data failed (%d)",err);
940 }
941 printsub(data, '>', &temp[2], len-2);
942 break;
943 }
944 return;
945 }
946
947
948 /*
949 * sendsuboption()
950 *
951 * Send suboption information to the server side.
952 */
953
sendsuboption(struct connectdata * conn,int option)954 static void sendsuboption(struct connectdata *conn, int option)
955 {
956 ssize_t bytes_written;
957 int err;
958 unsigned short x, y;
959 unsigned char *uc1, *uc2;
960
961 struct Curl_easy *data = conn->data;
962 struct TELNET *tn = (struct TELNET *)data->req.protop;
963
964 switch(option) {
965 case CURL_TELOPT_NAWS:
966 /* We prepare data to be sent */
967 CURL_SB_CLEAR(tn);
968 CURL_SB_ACCUM(tn, CURL_IAC);
969 CURL_SB_ACCUM(tn, CURL_SB);
970 CURL_SB_ACCUM(tn, CURL_TELOPT_NAWS);
971 /* We must deal either with little or big endian processors */
972 /* Window size must be sent according to the 'network order' */
973 x = htons(tn->subopt_wsx);
974 y = htons(tn->subopt_wsy);
975 uc1 = (unsigned char *)&x;
976 uc2 = (unsigned char *)&y;
977 CURL_SB_ACCUM(tn, uc1[0]);
978 CURL_SB_ACCUM(tn, uc1[1]);
979 CURL_SB_ACCUM(tn, uc2[0]);
980 CURL_SB_ACCUM(tn, uc2[1]);
981
982 CURL_SB_ACCUM(tn, CURL_IAC);
983 CURL_SB_ACCUM(tn, CURL_SE);
984 CURL_SB_TERM(tn);
985 /* data suboption is now ready */
986
987 printsub(data, '>', (unsigned char *)tn->subbuffer + 2,
988 CURL_SB_LEN(tn)-2);
989
990 /* we send the header of the suboption... */
991 bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer, 3);
992 if(bytes_written < 0) {
993 err = SOCKERRNO;
994 failf(data, "Sending data failed (%d)", err);
995 }
996 /* ... then the window size with the send_telnet_data() function
997 to deal with 0xFF cases ... */
998 send_telnet_data(conn, (char *)tn->subbuffer + 3, 4);
999 /* ... and the footer */
1000 bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer + 7, 2);
1001 if(bytes_written < 0) {
1002 err = SOCKERRNO;
1003 failf(data, "Sending data failed (%d)", err);
1004 }
1005 break;
1006 }
1007 }
1008
1009
1010 static
telrcv(struct connectdata * conn,const unsigned char * inbuf,ssize_t count)1011 CURLcode telrcv(struct connectdata *conn,
1012 const unsigned char *inbuf, /* Data received from socket */
1013 ssize_t count) /* Number of bytes received */
1014 {
1015 unsigned char c;
1016 CURLcode result;
1017 int in = 0;
1018 int startwrite = -1;
1019 struct Curl_easy *data = conn->data;
1020 struct TELNET *tn = (struct TELNET *)data->req.protop;
1021
1022 #define startskipping() \
1023 if(startwrite >= 0) { \
1024 result = Curl_client_write(conn, \
1025 CLIENTWRITE_BODY, \
1026 (char *)&inbuf[startwrite], \
1027 in-startwrite); \
1028 if(result) \
1029 return result; \
1030 } \
1031 startwrite = -1
1032
1033 #define writebyte() \
1034 if(startwrite < 0) \
1035 startwrite = in
1036
1037 #define bufferflush() startskipping()
1038
1039 while(count--) {
1040 c = inbuf[in];
1041
1042 switch(tn->telrcv_state) {
1043 case CURL_TS_CR:
1044 tn->telrcv_state = CURL_TS_DATA;
1045 if(c == '\0') {
1046 startskipping();
1047 break; /* Ignore \0 after CR */
1048 }
1049 writebyte();
1050 break;
1051
1052 case CURL_TS_DATA:
1053 if(c == CURL_IAC) {
1054 tn->telrcv_state = CURL_TS_IAC;
1055 startskipping();
1056 break;
1057 }
1058 else if(c == '\r')
1059 tn->telrcv_state = CURL_TS_CR;
1060 writebyte();
1061 break;
1062
1063 case CURL_TS_IAC:
1064 process_iac:
1065 DEBUGASSERT(startwrite < 0);
1066 switch(c) {
1067 case CURL_WILL:
1068 tn->telrcv_state = CURL_TS_WILL;
1069 break;
1070 case CURL_WONT:
1071 tn->telrcv_state = CURL_TS_WONT;
1072 break;
1073 case CURL_DO:
1074 tn->telrcv_state = CURL_TS_DO;
1075 break;
1076 case CURL_DONT:
1077 tn->telrcv_state = CURL_TS_DONT;
1078 break;
1079 case CURL_SB:
1080 CURL_SB_CLEAR(tn);
1081 tn->telrcv_state = CURL_TS_SB;
1082 break;
1083 case CURL_IAC:
1084 tn->telrcv_state = CURL_TS_DATA;
1085 writebyte();
1086 break;
1087 case CURL_DM:
1088 case CURL_NOP:
1089 case CURL_GA:
1090 default:
1091 tn->telrcv_state = CURL_TS_DATA;
1092 printoption(data, "RCVD", CURL_IAC, c);
1093 break;
1094 }
1095 break;
1096
1097 case CURL_TS_WILL:
1098 printoption(data, "RCVD", CURL_WILL, c);
1099 tn->please_negotiate = 1;
1100 rec_will(conn, c);
1101 tn->telrcv_state = CURL_TS_DATA;
1102 break;
1103
1104 case CURL_TS_WONT:
1105 printoption(data, "RCVD", CURL_WONT, c);
1106 tn->please_negotiate = 1;
1107 rec_wont(conn, c);
1108 tn->telrcv_state = CURL_TS_DATA;
1109 break;
1110
1111 case CURL_TS_DO:
1112 printoption(data, "RCVD", CURL_DO, c);
1113 tn->please_negotiate = 1;
1114 rec_do(conn, c);
1115 tn->telrcv_state = CURL_TS_DATA;
1116 break;
1117
1118 case CURL_TS_DONT:
1119 printoption(data, "RCVD", CURL_DONT, c);
1120 tn->please_negotiate = 1;
1121 rec_dont(conn, c);
1122 tn->telrcv_state = CURL_TS_DATA;
1123 break;
1124
1125 case CURL_TS_SB:
1126 if(c == CURL_IAC)
1127 tn->telrcv_state = CURL_TS_SE;
1128 else
1129 CURL_SB_ACCUM(tn, c);
1130 break;
1131
1132 case CURL_TS_SE:
1133 if(c != CURL_SE) {
1134 if(c != CURL_IAC) {
1135 /*
1136 * This is an error. We only expect to get "IAC IAC" or "IAC SE".
1137 * Several things may have happened. An IAC was not doubled, the
1138 * IAC SE was left off, or another option got inserted into the
1139 * suboption are all possibilities. If we assume that the IAC was
1140 * not doubled, and really the IAC SE was left off, we could get
1141 * into an infinite loop here. So, instead, we terminate the
1142 * suboption, and process the partial suboption if we can.
1143 */
1144 CURL_SB_ACCUM(tn, CURL_IAC);
1145 CURL_SB_ACCUM(tn, c);
1146 tn->subpointer -= 2;
1147 CURL_SB_TERM(tn);
1148
1149 printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c);
1150 suboption(conn); /* handle sub-option */
1151 tn->telrcv_state = CURL_TS_IAC;
1152 goto process_iac;
1153 }
1154 CURL_SB_ACCUM(tn, c);
1155 tn->telrcv_state = CURL_TS_SB;
1156 }
1157 else {
1158 CURL_SB_ACCUM(tn, CURL_IAC);
1159 CURL_SB_ACCUM(tn, CURL_SE);
1160 tn->subpointer -= 2;
1161 CURL_SB_TERM(tn);
1162 suboption(conn); /* handle sub-option */
1163 tn->telrcv_state = CURL_TS_DATA;
1164 }
1165 break;
1166 }
1167 ++in;
1168 }
1169 bufferflush();
1170 return CURLE_OK;
1171 }
1172
1173 /* Escape and send a telnet data block */
send_telnet_data(struct connectdata * conn,char * buffer,ssize_t nread)1174 static CURLcode send_telnet_data(struct connectdata *conn,
1175 char *buffer, ssize_t nread)
1176 {
1177 ssize_t escapes, i, outlen;
1178 unsigned char *outbuf = NULL;
1179 CURLcode result = CURLE_OK;
1180 ssize_t bytes_written, total_written;
1181
1182 /* Determine size of new buffer after escaping */
1183 escapes = 0;
1184 for(i = 0; i < nread; i++)
1185 if((unsigned char)buffer[i] == CURL_IAC)
1186 escapes++;
1187 outlen = nread + escapes;
1188
1189 if(outlen == nread)
1190 outbuf = (unsigned char *)buffer;
1191 else {
1192 ssize_t j;
1193 outbuf = malloc(nread + escapes + 1);
1194 if(!outbuf)
1195 return CURLE_OUT_OF_MEMORY;
1196
1197 j = 0;
1198 for(i = 0; i < nread; i++) {
1199 outbuf[j++] = buffer[i];
1200 if((unsigned char)buffer[i] == CURL_IAC)
1201 outbuf[j++] = CURL_IAC;
1202 }
1203 outbuf[j] = '\0';
1204 }
1205
1206 total_written = 0;
1207 while(!result && total_written < outlen) {
1208 /* Make sure socket is writable to avoid EWOULDBLOCK condition */
1209 struct pollfd pfd[1];
1210 pfd[0].fd = conn->sock[FIRSTSOCKET];
1211 pfd[0].events = POLLOUT;
1212 switch(Curl_poll(pfd, 1, -1)) {
1213 case -1: /* error, abort writing */
1214 case 0: /* timeout (will never happen) */
1215 result = CURLE_SEND_ERROR;
1216 break;
1217 default: /* write! */
1218 bytes_written = 0;
1219 result = Curl_write(conn, conn->sock[FIRSTSOCKET],
1220 outbuf + total_written,
1221 outlen - total_written,
1222 &bytes_written);
1223 total_written += bytes_written;
1224 break;
1225 }
1226 }
1227
1228 /* Free malloc copy if escaped */
1229 if(outbuf != (unsigned char *)buffer)
1230 free(outbuf);
1231
1232 return result;
1233 }
1234
telnet_done(struct connectdata * conn,CURLcode status,bool premature)1235 static CURLcode telnet_done(struct connectdata *conn,
1236 CURLcode status, bool premature)
1237 {
1238 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
1239 (void)status; /* unused */
1240 (void)premature; /* not used */
1241
1242 if(!tn)
1243 return CURLE_OK;
1244
1245 curl_slist_free_all(tn->telnet_vars);
1246 tn->telnet_vars = NULL;
1247
1248 Curl_safefree(conn->data->req.protop);
1249
1250 return CURLE_OK;
1251 }
1252
telnet_do(struct connectdata * conn,bool * done)1253 static CURLcode telnet_do(struct connectdata *conn, bool *done)
1254 {
1255 CURLcode result;
1256 struct Curl_easy *data = conn->data;
1257 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
1258 #ifdef USE_WINSOCK
1259 WSAEVENT event_handle;
1260 WSANETWORKEVENTS events;
1261 HANDLE stdin_handle;
1262 HANDLE objs[2];
1263 DWORD obj_count;
1264 DWORD wait_timeout;
1265 DWORD readfile_read;
1266 int err;
1267 #else
1268 timediff_t interval_ms;
1269 struct pollfd pfd[2];
1270 int poll_cnt;
1271 curl_off_t total_dl = 0;
1272 curl_off_t total_ul = 0;
1273 #endif
1274 ssize_t nread;
1275 struct curltime now;
1276 bool keepon = TRUE;
1277 char *buf = data->state.buffer;
1278 struct TELNET *tn;
1279
1280 *done = TRUE; /* unconditionally */
1281
1282 result = init_telnet(conn);
1283 if(result)
1284 return result;
1285
1286 tn = (struct TELNET *)data->req.protop;
1287
1288 result = check_telnet_options(conn);
1289 if(result)
1290 return result;
1291
1292 #ifdef USE_WINSOCK
1293 /* We want to wait for both stdin and the socket. Since
1294 ** the select() function in winsock only works on sockets
1295 ** we have to use the WaitForMultipleObjects() call.
1296 */
1297
1298 /* First, create a sockets event object */
1299 event_handle = WSACreateEvent();
1300 if(event_handle == WSA_INVALID_EVENT) {
1301 failf(data, "WSACreateEvent failed (%d)", SOCKERRNO);
1302 return CURLE_FAILED_INIT;
1303 }
1304
1305 /* Tell winsock what events we want to listen to */
1306 if(WSAEventSelect(sockfd, event_handle, FD_READ|FD_CLOSE) == SOCKET_ERROR) {
1307 WSACloseEvent(event_handle);
1308 return CURLE_OK;
1309 }
1310
1311 /* The get the Windows file handle for stdin */
1312 stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
1313
1314 /* Create the list of objects to wait for */
1315 objs[0] = event_handle;
1316 objs[1] = stdin_handle;
1317
1318 /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
1319 else use the old WaitForMultipleObjects() way */
1320 if(GetFileType(stdin_handle) == FILE_TYPE_PIPE ||
1321 data->set.is_fread_set) {
1322 /* Don't wait for stdin_handle, just wait for event_handle */
1323 obj_count = 1;
1324 /* Check stdin_handle per 100 milliseconds */
1325 wait_timeout = 100;
1326 }
1327 else {
1328 obj_count = 2;
1329 wait_timeout = 1000;
1330 }
1331
1332 /* Keep on listening and act on events */
1333 while(keepon) {
1334 const DWORD buf_size = (DWORD)data->set.buffer_size;
1335 DWORD waitret = WaitForMultipleObjects(obj_count, objs,
1336 FALSE, wait_timeout);
1337 switch(waitret) {
1338
1339 case WAIT_TIMEOUT:
1340 {
1341 for(;;) {
1342 if(data->set.is_fread_set) {
1343 size_t n;
1344 /* read from user-supplied method */
1345 n = data->state.fread_func(buf, 1, buf_size, data->state.in);
1346 if(n == CURL_READFUNC_ABORT) {
1347 keepon = FALSE;
1348 result = CURLE_READ_ERROR;
1349 break;
1350 }
1351
1352 if(n == CURL_READFUNC_PAUSE)
1353 break;
1354
1355 if(n == 0) /* no bytes */
1356 break;
1357
1358 /* fall through with number of bytes read */
1359 readfile_read = (DWORD)n;
1360 }
1361 else {
1362 /* read from stdin */
1363 if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL,
1364 &readfile_read, NULL)) {
1365 keepon = FALSE;
1366 result = CURLE_READ_ERROR;
1367 break;
1368 }
1369
1370 if(!readfile_read)
1371 break;
1372
1373 if(!ReadFile(stdin_handle, buf, buf_size,
1374 &readfile_read, NULL)) {
1375 keepon = FALSE;
1376 result = CURLE_READ_ERROR;
1377 break;
1378 }
1379 }
1380
1381 result = send_telnet_data(conn, buf, readfile_read);
1382 if(result) {
1383 keepon = FALSE;
1384 break;
1385 }
1386 }
1387 }
1388 break;
1389
1390 case WAIT_OBJECT_0 + 1:
1391 {
1392 if(!ReadFile(stdin_handle, buf, buf_size,
1393 &readfile_read, NULL)) {
1394 keepon = FALSE;
1395 result = CURLE_READ_ERROR;
1396 break;
1397 }
1398
1399 result = send_telnet_data(conn, buf, readfile_read);
1400 if(result) {
1401 keepon = FALSE;
1402 break;
1403 }
1404 }
1405 break;
1406
1407 case WAIT_OBJECT_0:
1408 {
1409 events.lNetworkEvents = 0;
1410 if(WSAEnumNetworkEvents(sockfd, event_handle, &events) == SOCKET_ERROR) {
1411 err = SOCKERRNO;
1412 if(err != EINPROGRESS) {
1413 infof(data, "WSAEnumNetworkEvents failed (%d)", err);
1414 keepon = FALSE;
1415 result = CURLE_READ_ERROR;
1416 }
1417 break;
1418 }
1419 if(events.lNetworkEvents & FD_READ) {
1420 /* read data from network */
1421 result = Curl_read(conn, sockfd, buf, data->set.buffer_size, &nread);
1422 /* read would've blocked. Loop again */
1423 if(result == CURLE_AGAIN)
1424 break;
1425 /* returned not-zero, this an error */
1426 else if(result) {
1427 keepon = FALSE;
1428 break;
1429 }
1430 /* returned zero but actually received 0 or less here,
1431 the server closed the connection and we bail out */
1432 else if(nread <= 0) {
1433 keepon = FALSE;
1434 break;
1435 }
1436
1437 result = telrcv(conn, (unsigned char *) buf, nread);
1438 if(result) {
1439 keepon = FALSE;
1440 break;
1441 }
1442
1443 /* Negotiate if the peer has started negotiating,
1444 otherwise don't. We don't want to speak telnet with
1445 non-telnet servers, like POP or SMTP. */
1446 if(tn->please_negotiate && !tn->already_negotiated) {
1447 negotiate(conn);
1448 tn->already_negotiated = 1;
1449 }
1450 }
1451 if(events.lNetworkEvents & FD_CLOSE) {
1452 keepon = FALSE;
1453 }
1454 }
1455 break;
1456
1457 }
1458
1459 if(data->set.timeout) {
1460 now = Curl_now();
1461 if(Curl_timediff(now, conn->created) >= data->set.timeout) {
1462 failf(data, "Time-out");
1463 result = CURLE_OPERATION_TIMEDOUT;
1464 keepon = FALSE;
1465 }
1466 }
1467 }
1468
1469 /* We called WSACreateEvent, so call WSACloseEvent */
1470 if(!WSACloseEvent(event_handle)) {
1471 infof(data, "WSACloseEvent failed (%d)", SOCKERRNO);
1472 }
1473 #else
1474 pfd[0].fd = sockfd;
1475 pfd[0].events = POLLIN;
1476
1477 if(data->set.is_fread_set) {
1478 poll_cnt = 1;
1479 interval_ms = 100; /* poll user-supplied read function */
1480 }
1481 else {
1482 /* really using fread, so infile is a FILE* */
1483 pfd[1].fd = fileno((FILE *)data->state.in);
1484 pfd[1].events = POLLIN;
1485 poll_cnt = 2;
1486 interval_ms = 1 * 1000;
1487 }
1488
1489 while(keepon) {
1490 switch(Curl_poll(pfd, poll_cnt, interval_ms)) {
1491 case -1: /* error, stop reading */
1492 keepon = FALSE;
1493 continue;
1494 case 0: /* timeout */
1495 pfd[0].revents = 0;
1496 pfd[1].revents = 0;
1497 /* FALLTHROUGH */
1498 default: /* read! */
1499 if(pfd[0].revents & POLLIN) {
1500 /* read data from network */
1501 result = Curl_read(conn, sockfd, buf, data->set.buffer_size, &nread);
1502 /* read would've blocked. Loop again */
1503 if(result == CURLE_AGAIN)
1504 break;
1505 /* returned not-zero, this an error */
1506 if(result) {
1507 keepon = FALSE;
1508 break;
1509 }
1510 /* returned zero but actually received 0 or less here,
1511 the server closed the connection and we bail out */
1512 else if(nread <= 0) {
1513 keepon = FALSE;
1514 break;
1515 }
1516
1517 total_dl += nread;
1518 Curl_pgrsSetDownloadCounter(data, total_dl);
1519 result = telrcv(conn, (unsigned char *)buf, nread);
1520 if(result) {
1521 keepon = FALSE;
1522 break;
1523 }
1524
1525 /* Negotiate if the peer has started negotiating,
1526 otherwise don't. We don't want to speak telnet with
1527 non-telnet servers, like POP or SMTP. */
1528 if(tn->please_negotiate && !tn->already_negotiated) {
1529 negotiate(conn);
1530 tn->already_negotiated = 1;
1531 }
1532 }
1533
1534 nread = 0;
1535 if(poll_cnt == 2) {
1536 if(pfd[1].revents & POLLIN) { /* read from in file */
1537 nread = read(pfd[1].fd, buf, data->set.buffer_size);
1538 }
1539 }
1540 else {
1541 /* read from user-supplied method */
1542 nread = (int)data->state.fread_func(buf, 1, data->set.buffer_size,
1543 data->state.in);
1544 if(nread == CURL_READFUNC_ABORT) {
1545 keepon = FALSE;
1546 break;
1547 }
1548 if(nread == CURL_READFUNC_PAUSE)
1549 break;
1550 }
1551
1552 if(nread > 0) {
1553 result = send_telnet_data(conn, buf, nread);
1554 if(result) {
1555 keepon = FALSE;
1556 break;
1557 }
1558 total_ul += nread;
1559 Curl_pgrsSetUploadCounter(data, total_ul);
1560 }
1561 else if(nread < 0)
1562 keepon = FALSE;
1563
1564 break;
1565 } /* poll switch statement */
1566
1567 if(data->set.timeout) {
1568 now = Curl_now();
1569 if(Curl_timediff(now, conn->created) >= data->set.timeout) {
1570 failf(data, "Time-out");
1571 result = CURLE_OPERATION_TIMEDOUT;
1572 keepon = FALSE;
1573 }
1574 }
1575
1576 if(Curl_pgrsUpdate(conn)) {
1577 result = CURLE_ABORTED_BY_CALLBACK;
1578 break;
1579 }
1580 }
1581 #endif
1582 /* mark this as "no further transfer wanted" */
1583 Curl_setup_transfer(data, -1, -1, FALSE, -1);
1584
1585 return result;
1586 }
1587 #endif
1588