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