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