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