VirtualBox

source: vbox/trunk/src/libs/curl-7.87.0/lib/telnet.c@ 99040

最後變更 在這個檔案從99040是 98326,由 vboxsync 提交於 2 年 前

curl-7.87.0: Applied and adjusted our curl changes to 7.83.1. bugref:10356

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette