source: asp3_tinet_ecnl_arm/trunk/curl-7.57.0/lib/telnet.c@ 352

Last change on this file since 352 was 352, checked in by coas-nagasima, 6 years ago

arm向けASP3版ECNLを追加

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