VirtualBox

source: vbox/trunk/src/libs/curl-8.7.1/lib/telnet.c@ 106165

最後變更 在這個檔案從106165是 104083,由 vboxsync 提交於 8 月 前

curl-8.7.1: Applied and adjusted our curl changes to 8.4.0. bugref:10639

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

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