1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2016, 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 "strequal.h"
62 #include "rawstr.h"
63 #include "warnless.h"
64
65 /* The last 3 #include files should be in this order */
66 #include "curl_printf.h"
67 #include "curl_memory.h"
68 #include "memdebug.h"
69
70 #define SUBBUFSIZE 512
71
72 #define CURL_SB_CLEAR(x) x->subpointer = x->subbuffer
73 #define CURL_SB_TERM(x) \
74 do { \
75 x->subend = x->subpointer; \
76 CURL_SB_CLEAR(x); \
77 } WHILE_FALSE
78 #define CURL_SB_ACCUM(x,c) \
79 do { \
80 if(x->subpointer < (x->subbuffer+sizeof x->subbuffer)) \
81 *x->subpointer++ = (c); \
82 } WHILE_FALSE
83
84 #define CURL_SB_GET(x) ((*x->subpointer++)&0xff)
85 #define CURL_SB_PEEK(x) ((*x->subpointer)&0xff)
86 #define CURL_SB_EOF(x) (x->subpointer >= x->subend)
87 #define CURL_SB_LEN(x) (x->subend - x->subpointer)
88
89 #ifdef CURL_DISABLE_VERBOSE_STRINGS
90 #define printoption(a,b,c,d) Curl_nop_stmt
91 #endif
92
93 #ifdef USE_WINSOCK
94 typedef FARPROC WSOCK2_FUNC;
95 static CURLcode check_wsock2 (struct Curl_easy *data);
96 #endif
97
98 static
99 CURLcode telrcv(struct connectdata *,
100 const unsigned char *inbuf, /* Data received from socket */
101 ssize_t count); /* Number of bytes received */
102
103 #ifndef CURL_DISABLE_VERBOSE_STRINGS
104 static void printoption(struct Curl_easy *data,
105 const char *direction,
106 int cmd, int option);
107 #endif
108
109 static void negotiate(struct connectdata *);
110 static void send_negotiation(struct connectdata *, int cmd, int option);
111 static void set_local_option(struct connectdata *, int cmd, int option);
112 static void set_remote_option(struct connectdata *, int cmd, int option);
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 PORT_TELNET, /* defport */
195 CURLPROTO_TELNET, /* protocol */
196 PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */
197 };
198
199
200 #ifdef USE_WINSOCK
201 static CURLcode
check_wsock2(struct Curl_easy * data)202 check_wsock2(struct Curl_easy *data)
203 {
204 int err;
205 WORD wVersionRequested;
206 WSADATA wsaData;
207
208 DEBUGASSERT(data);
209
210 /* telnet requires at least WinSock 2.0 so ask for it. */
211 wVersionRequested = MAKEWORD(2, 0);
212
213 err = WSAStartup(wVersionRequested, &wsaData);
214
215 /* We must've called this once already, so this call */
216 /* should always succeed. But, just in case... */
217 if(err != 0) {
218 failf(data,"WSAStartup failed (%d)",err);
219 return CURLE_FAILED_INIT;
220 }
221
222 /* We have to have a WSACleanup call for every successful */
223 /* WSAStartup call. */
224 WSACleanup();
225
226 /* Check that our version is supported */
227 if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
228 HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested)) {
229 /* Our version isn't supported */
230 failf(data, "insufficient winsock version to support "
231 "telnet");
232 return CURLE_FAILED_INIT;
233 }
234
235 /* Our version is supported */
236 return CURLE_OK;
237 }
238 #endif
239
240 static
init_telnet(struct connectdata * conn)241 CURLcode init_telnet(struct connectdata *conn)
242 {
243 struct TELNET *tn;
244
245 tn = calloc(1, sizeof(struct TELNET));
246 if(!tn)
247 return CURLE_OUT_OF_MEMORY;
248
249 conn->data->req.protop = tn; /* make us known */
250
251 tn->telrcv_state = CURL_TS_DATA;
252
253 /* Init suboptions */
254 CURL_SB_CLEAR(tn);
255
256 /* Set the options we want by default */
257 tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES;
258 tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES;
259
260 /* To be compliant with previous releases of libcurl
261 we enable this option by default. This behaviour
262 can be changed thanks to the "BINARY" option in
263 CURLOPT_TELNETOPTIONS
264 */
265 tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES;
266 tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES;
267
268 /* We must allow the server to echo what we sent
269 but it is not necessary to request the server
270 to do so (it might forces the server to close
271 the connection). Hence, we ignore ECHO in the
272 negotiate function
273 */
274 tn->him_preferred[CURL_TELOPT_ECHO] = CURL_YES;
275
276 /* Set the subnegotiation fields to send information
277 just after negotiation passed (do/will)
278
279 Default values are (0,0) initialized by calloc.
280 According to the RFC1013 it is valid:
281 A value equal to zero is acceptable for the width (or height),
282 and means that no character width (or height) is being sent.
283 In this case, the width (or height) that will be assumed by the
284 Telnet server is operating system specific (it will probably be
285 based upon the terminal type information that may have been sent
286 using the TERMINAL TYPE Telnet option). */
287 tn->subnegotiation[CURL_TELOPT_NAWS] = CURL_YES;
288 return CURLE_OK;
289 }
290
negotiate(struct connectdata * conn)291 static void negotiate(struct connectdata *conn)
292 {
293 int i;
294 struct TELNET *tn = (struct TELNET *) conn->data->req.protop;
295
296 for(i = 0;i < CURL_NTELOPTS;i++) {
297 if(i==CURL_TELOPT_ECHO)
298 continue;
299
300 if(tn->us_preferred[i] == CURL_YES)
301 set_local_option(conn, i, CURL_YES);
302
303 if(tn->him_preferred[i] == CURL_YES)
304 set_remote_option(conn, i, CURL_YES);
305 }
306 }
307
308 #ifndef CURL_DISABLE_VERBOSE_STRINGS
printoption(struct Curl_easy * data,const char * direction,int cmd,int option)309 static void printoption(struct Curl_easy *data,
310 const char *direction, int cmd, int option)
311 {
312 const char *fmt;
313 const char *opt;
314
315 if(data->set.verbose) {
316 if(cmd == CURL_IAC) {
317 if(CURL_TELCMD_OK(option))
318 infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option));
319 else
320 infof(data, "%s IAC %d\n", direction, option);
321 }
322 else {
323 fmt = (cmd == CURL_WILL) ? "WILL" : (cmd == CURL_WONT) ? "WONT" :
324 (cmd == CURL_DO) ? "DO" : (cmd == CURL_DONT) ? "DONT" : 0;
325 if(fmt) {
326 if(CURL_TELOPT_OK(option))
327 opt = CURL_TELOPT(option);
328 else if(option == CURL_TELOPT_EXOPL)
329 opt = "EXOPL";
330 else
331 opt = NULL;
332
333 if(opt)
334 infof(data, "%s %s %s\n", direction, fmt, opt);
335 else
336 infof(data, "%s %s %d\n", direction, fmt, option);
337 }
338 else
339 infof(data, "%s %d %d\n", direction, cmd, option);
340 }
341 }
342 }
343 #endif
344
send_negotiation(struct connectdata * conn,int cmd,int option)345 static void send_negotiation(struct connectdata *conn, int cmd, int option)
346 {
347 unsigned char buf[3];
348 ssize_t bytes_written;
349 int err;
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 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 unsigned int i = 0;
712
713 if(data->set.verbose) {
714 if(direction) {
715 infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
716 if(length >= 3) {
717 int j;
718
719 i = pointer[length-2];
720 j = pointer[length-1];
721
722 if(i != CURL_IAC || j != CURL_SE) {
723 infof(data, "(terminated by ");
724 if(CURL_TELOPT_OK(i))
725 infof(data, "%s ", CURL_TELOPT(i));
726 else if(CURL_TELCMD_OK(i))
727 infof(data, "%s ", CURL_TELCMD(i));
728 else
729 infof(data, "%u ", i);
730 if(CURL_TELOPT_OK(j))
731 infof(data, "%s", CURL_TELOPT(j));
732 else if(CURL_TELCMD_OK(j))
733 infof(data, "%s", CURL_TELCMD(j));
734 else
735 infof(data, "%d", j);
736 infof(data, ", not IAC SE!) ");
737 }
738 }
739 length -= 2;
740 }
741 if(length < 1) {
742 infof(data, "(Empty suboption?)");
743 return;
744 }
745
746 if(CURL_TELOPT_OK(pointer[0])) {
747 switch(pointer[0]) {
748 case CURL_TELOPT_TTYPE:
749 case CURL_TELOPT_XDISPLOC:
750 case CURL_TELOPT_NEW_ENVIRON:
751 case CURL_TELOPT_NAWS:
752 infof(data, "%s", CURL_TELOPT(pointer[0]));
753 break;
754 default:
755 infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
756 break;
757 }
758 }
759 else
760 infof(data, "%d (unknown)", pointer[i]);
761
762 switch(pointer[0]) {
763 case CURL_TELOPT_NAWS:
764 if(length > 4)
765 infof(data, "Width: %hu ; Height: %hu", (pointer[1]<<8) | pointer[2],
766 (pointer[3]<<8) | pointer[4]);
767 break;
768 default:
769 switch(pointer[1]) {
770 case CURL_TELQUAL_IS:
771 infof(data, " IS");
772 break;
773 case CURL_TELQUAL_SEND:
774 infof(data, " SEND");
775 break;
776 case CURL_TELQUAL_INFO:
777 infof(data, " INFO/REPLY");
778 break;
779 case CURL_TELQUAL_NAME:
780 infof(data, " NAME");
781 break;
782 }
783
784 switch(pointer[0]) {
785 case CURL_TELOPT_TTYPE:
786 case CURL_TELOPT_XDISPLOC:
787 pointer[length] = 0;
788 infof(data, " \"%s\"", &pointer[2]);
789 break;
790 case CURL_TELOPT_NEW_ENVIRON:
791 if(pointer[1] == CURL_TELQUAL_IS) {
792 infof(data, " ");
793 for(i = 3;i < length;i++) {
794 switch(pointer[i]) {
795 case CURL_NEW_ENV_VAR:
796 infof(data, ", ");
797 break;
798 case CURL_NEW_ENV_VALUE:
799 infof(data, " = ");
800 break;
801 default:
802 infof(data, "%c", pointer[i]);
803 break;
804 }
805 }
806 }
807 break;
808 default:
809 for(i = 2; i < length; i++)
810 infof(data, " %.2x", pointer[i]);
811 break;
812 }
813 }
814 if(direction)
815 infof(data, "\n");
816 }
817 }
818
check_telnet_options(struct connectdata * conn)819 static CURLcode check_telnet_options(struct connectdata *conn)
820 {
821 struct curl_slist *head;
822 struct curl_slist *beg;
823 char option_keyword[128] = "";
824 char option_arg[256] = "";
825 struct Curl_easy *data = conn->data;
826 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
827 CURLcode result = CURLE_OK;
828 int binary_option;
829
830 /* Add the user name as an environment variable if it
831 was given on the command line */
832 if(conn->bits.user_passwd) {
833 snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
834 beg = curl_slist_append(tn->telnet_vars, option_arg);
835 if(!beg) {
836 curl_slist_free_all(tn->telnet_vars);
837 tn->telnet_vars = NULL;
838 return CURLE_OUT_OF_MEMORY;
839 }
840 tn->telnet_vars = beg;
841 tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
842 }
843
844 for(head = data->set.telnet_options; head; head=head->next) {
845 if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
846 option_keyword, option_arg) == 2) {
847
848 /* Terminal type */
849 if(Curl_raw_equal(option_keyword, "TTYPE")) {
850 strncpy(tn->subopt_ttype, option_arg, 31);
851 tn->subopt_ttype[31] = 0; /* String termination */
852 tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
853 continue;
854 }
855
856 /* Display variable */
857 if(Curl_raw_equal(option_keyword, "XDISPLOC")) {
858 strncpy(tn->subopt_xdisploc, option_arg, 127);
859 tn->subopt_xdisploc[127] = 0; /* String termination */
860 tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
861 continue;
862 }
863
864 /* Environment variable */
865 if(Curl_raw_equal(option_keyword, "NEW_ENV")) {
866 beg = curl_slist_append(tn->telnet_vars, option_arg);
867 if(!beg) {
868 result = CURLE_OUT_OF_MEMORY;
869 break;
870 }
871 tn->telnet_vars = beg;
872 tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
873 continue;
874 }
875
876 /* Window Size */
877 if(Curl_raw_equal(option_keyword, "WS")) {
878 if(sscanf(option_arg, "%hu%*[xX]%hu",
879 &tn->subopt_wsx, &tn->subopt_wsy) == 2)
880 tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
881 else {
882 failf(data, "Syntax error in telnet option: %s", head->data);
883 result = CURLE_TELNET_OPTION_SYNTAX;
884 break;
885 }
886 continue;
887 }
888
889 /* To take care or not of the 8th bit in data exchange */
890 if(Curl_raw_equal(option_keyword, "BINARY")) {
891 binary_option=atoi(option_arg);
892 if(binary_option!=1) {
893 tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO;
894 tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO;
895 }
896 continue;
897 }
898
899 failf(data, "Unknown telnet option %s", head->data);
900 result = CURLE_UNKNOWN_TELNET_OPTION;
901 break;
902 }
903 else {
904 failf(data, "Syntax error in telnet option: %s", head->data);
905 result = CURLE_TELNET_OPTION_SYNTAX;
906 break;
907 }
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
suboption(struct connectdata * conn)925 static 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
sendsuboption(struct connectdata * conn,int option)1003 static 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 endien 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
1059 static
telrcv(struct connectdata * conn,const unsigned char * inbuf,ssize_t count)1060 CURLcode 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 infinate 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 */
1224 /* TODO: write large chunks of data instead of one byte at a time */
send_telnet_data(struct connectdata * conn,char * buffer,ssize_t nread)1225 static CURLcode send_telnet_data(struct connectdata *conn,
1226 char *buffer, ssize_t nread)
1227 {
1228 unsigned char outbuf[2];
1229 ssize_t bytes_written, total_written;
1230 int out_count;
1231 CURLcode result = CURLE_OK;
1232
1233 while(!result && nread--) {
1234 outbuf[0] = *buffer++;
1235 out_count = 1;
1236 if(outbuf[0] == CURL_IAC)
1237 outbuf[out_count++] = CURL_IAC;
1238
1239 total_written = 0;
1240 do {
1241 /* Make sure socket is writable to avoid EWOULDBLOCK condition */
1242 struct pollfd pfd[1];
1243 pfd[0].fd = conn->sock[FIRSTSOCKET];
1244 pfd[0].events = POLLOUT;
1245 switch (Curl_poll(pfd, 1, -1)) {
1246 case -1: /* error, abort writing */
1247 case 0: /* timeout (will never happen) */
1248 result = CURLE_SEND_ERROR;
1249 break;
1250 default: /* write! */
1251 bytes_written = 0;
1252 result = Curl_write(conn, conn->sock[FIRSTSOCKET],
1253 outbuf+total_written, out_count-total_written,
1254 &bytes_written);
1255 total_written += bytes_written;
1256 break;
1257 }
1258 /* handle partial write */
1259 } while(!result && total_written < out_count);
1260 }
1261 return result;
1262 }
1263
telnet_done(struct connectdata * conn,CURLcode status,bool premature)1264 static CURLcode telnet_done(struct connectdata *conn,
1265 CURLcode status, bool premature)
1266 {
1267 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
1268 (void)status; /* unused */
1269 (void)premature; /* not used */
1270
1271 if(!tn)
1272 return CURLE_OK;
1273
1274 curl_slist_free_all(tn->telnet_vars);
1275 tn->telnet_vars = NULL;
1276
1277 Curl_safefree(conn->data->req.protop);
1278
1279 return CURLE_OK;
1280 }
1281
telnet_do(struct connectdata * conn,bool * done)1282 static CURLcode telnet_do(struct connectdata *conn, bool *done)
1283 {
1284 CURLcode result;
1285 struct Curl_easy *data = conn->data;
1286 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
1287 #ifdef USE_WINSOCK
1288 HMODULE wsock2;
1289 WSOCK2_FUNC close_event_func;
1290 WSOCK2_FUNC create_event_func;
1291 WSOCK2_FUNC event_select_func;
1292 WSOCK2_FUNC enum_netevents_func;
1293 WSAEVENT event_handle;
1294 WSANETWORKEVENTS events;
1295 HANDLE stdin_handle;
1296 HANDLE objs[2];
1297 DWORD obj_count;
1298 DWORD wait_timeout;
1299 DWORD waitret;
1300 DWORD readfile_read;
1301 int err;
1302 #else
1303 int interval_ms;
1304 struct pollfd pfd[2];
1305 int poll_cnt;
1306 curl_off_t total_dl = 0;
1307 curl_off_t total_ul = 0;
1308 #endif
1309 ssize_t nread;
1310 struct timeval now;
1311 bool keepon = TRUE;
1312 char *buf = data->state.buffer;
1313 struct TELNET *tn;
1314
1315 *done = TRUE; /* unconditionally */
1316
1317 result = init_telnet(conn);
1318 if(result)
1319 return result;
1320
1321 tn = (struct TELNET *)data->req.protop;
1322
1323 result = check_telnet_options(conn);
1324 if(result)
1325 return result;
1326
1327 #ifdef USE_WINSOCK
1328 /*
1329 ** This functionality only works with WinSock >= 2.0. So,
1330 ** make sure have it.
1331 */
1332 result = check_wsock2(data);
1333 if(result)
1334 return result;
1335
1336 /* OK, so we have WinSock 2.0. We need to dynamically */
1337 /* load ws2_32.dll and get the function pointers we need. */
1338 wsock2 = Curl_load_library(TEXT("WS2_32.DLL"));
1339 if(wsock2 == NULL) {
1340 failf(data, "failed to load WS2_32.DLL (%d)", ERRNO);
1341 return CURLE_FAILED_INIT;
1342 }
1343
1344 /* Grab a pointer to WSACreateEvent */
1345 create_event_func = GetProcAddress(wsock2, "WSACreateEvent");
1346 if(create_event_func == NULL) {
1347 failf(data, "failed to find WSACreateEvent function (%d)", ERRNO);
1348 FreeLibrary(wsock2);
1349 return CURLE_FAILED_INIT;
1350 }
1351
1352 /* And WSACloseEvent */
1353 close_event_func = GetProcAddress(wsock2, "WSACloseEvent");
1354 if(close_event_func == NULL) {
1355 failf(data, "failed to find WSACloseEvent function (%d)", ERRNO);
1356 FreeLibrary(wsock2);
1357 return CURLE_FAILED_INIT;
1358 }
1359
1360 /* And WSAEventSelect */
1361 event_select_func = GetProcAddress(wsock2, "WSAEventSelect");
1362 if(event_select_func == NULL) {
1363 failf(data, "failed to find WSAEventSelect function (%d)", ERRNO);
1364 FreeLibrary(wsock2);
1365 return CURLE_FAILED_INIT;
1366 }
1367
1368 /* And WSAEnumNetworkEvents */
1369 enum_netevents_func = GetProcAddress(wsock2, "WSAEnumNetworkEvents");
1370 if(enum_netevents_func == NULL) {
1371 failf(data, "failed to find WSAEnumNetworkEvents function (%d)", ERRNO);
1372 FreeLibrary(wsock2);
1373 return CURLE_FAILED_INIT;
1374 }
1375
1376 /* We want to wait for both stdin and the socket. Since
1377 ** the select() function in winsock only works on sockets
1378 ** we have to use the WaitForMultipleObjects() call.
1379 */
1380
1381 /* First, create a sockets event object */
1382 event_handle = (WSAEVENT)create_event_func();
1383 if(event_handle == WSA_INVALID_EVENT) {
1384 failf(data, "WSACreateEvent failed (%d)", SOCKERRNO);
1385 FreeLibrary(wsock2);
1386 return CURLE_FAILED_INIT;
1387 }
1388
1389 /* Tell winsock what events we want to listen to */
1390 if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) ==
1391 SOCKET_ERROR) {
1392 close_event_func(event_handle);
1393 FreeLibrary(wsock2);
1394 return CURLE_OK;
1395 }
1396
1397 /* The get the Windows file handle for stdin */
1398 stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
1399
1400 /* Create the list of objects to wait for */
1401 objs[0] = event_handle;
1402 objs[1] = stdin_handle;
1403
1404 /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
1405 else use the old WaitForMultipleObjects() way */
1406 if(GetFileType(stdin_handle) == FILE_TYPE_PIPE ||
1407 data->set.is_fread_set) {
1408 /* Don't wait for stdin_handle, just wait for event_handle */
1409 obj_count = 1;
1410 /* Check stdin_handle per 100 milliseconds */
1411 wait_timeout = 100;
1412 }
1413 else {
1414 obj_count = 2;
1415 wait_timeout = 1000;
1416 }
1417
1418 /* Keep on listening and act on events */
1419 while(keepon) {
1420 waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout);
1421 switch(waitret) {
1422 case WAIT_TIMEOUT:
1423 {
1424 for(;;) {
1425 if(data->set.is_fread_set) {
1426 /* read from user-supplied method */
1427 result = (int)data->state.fread_func(buf, 1, BUFSIZE - 1,
1428 data->state.in);
1429 if(result == CURL_READFUNC_ABORT) {
1430 keepon = FALSE;
1431 result = CURLE_READ_ERROR;
1432 break;
1433 }
1434
1435 if(result == CURL_READFUNC_PAUSE)
1436 break;
1437
1438 if(result == 0) /* no bytes */
1439 break;
1440
1441 readfile_read = result; /* fall thru with number of bytes read */
1442 }
1443 else {
1444 /* read from stdin */
1445 if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL,
1446 &readfile_read, NULL)) {
1447 keepon = FALSE;
1448 result = CURLE_READ_ERROR;
1449 break;
1450 }
1451
1452 if(!readfile_read)
1453 break;
1454
1455 if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
1456 &readfile_read, NULL)) {
1457 keepon = FALSE;
1458 result = CURLE_READ_ERROR;
1459 break;
1460 }
1461 }
1462
1463 result = send_telnet_data(conn, buf, readfile_read);
1464 if(result) {
1465 keepon = FALSE;
1466 break;
1467 }
1468 }
1469 }
1470 break;
1471
1472 case WAIT_OBJECT_0 + 1:
1473 {
1474 if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
1475 &readfile_read, NULL)) {
1476 keepon = FALSE;
1477 result = CURLE_READ_ERROR;
1478 break;
1479 }
1480
1481 result = send_telnet_data(conn, buf, readfile_read);
1482 if(result) {
1483 keepon = FALSE;
1484 break;
1485 }
1486 }
1487 break;
1488
1489 case WAIT_OBJECT_0:
1490
1491 events.lNetworkEvents = 0;
1492 if(SOCKET_ERROR == enum_netevents_func(sockfd, event_handle, &events)) {
1493 if((err = SOCKERRNO) != EINPROGRESS) {
1494 infof(data, "WSAEnumNetworkEvents failed (%d)", err);
1495 keepon = FALSE;
1496 result = CURLE_READ_ERROR;
1497 }
1498 break;
1499 }
1500 if(events.lNetworkEvents & FD_READ) {
1501 /* read data from network */
1502 result = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
1503 /* read would've blocked. Loop again */
1504 if(result == CURLE_AGAIN)
1505 break;
1506 /* returned not-zero, this an error */
1507 else if(result) {
1508 keepon = FALSE;
1509 break;
1510 }
1511 /* returned zero but actually received 0 or less here,
1512 the server closed the connection and we bail out */
1513 else if(nread <= 0) {
1514 keepon = FALSE;
1515 break;
1516 }
1517
1518 result = telrcv(conn, (unsigned char *) buf, nread);
1519 if(result) {
1520 keepon = FALSE;
1521 break;
1522 }
1523
1524 /* Negotiate if the peer has started negotiating,
1525 otherwise don't. We don't want to speak telnet with
1526 non-telnet servers, like POP or SMTP. */
1527 if(tn->please_negotiate && !tn->already_negotiated) {
1528 negotiate(conn);
1529 tn->already_negotiated = 1;
1530 }
1531 }
1532 if(events.lNetworkEvents & FD_CLOSE) {
1533 keepon = FALSE;
1534 }
1535 break;
1536
1537 }
1538
1539 if(data->set.timeout) {
1540 now = Curl_tvnow();
1541 if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
1542 failf(data, "Time-out");
1543 result = CURLE_OPERATION_TIMEDOUT;
1544 keepon = FALSE;
1545 }
1546 }
1547 }
1548
1549 /* We called WSACreateEvent, so call WSACloseEvent */
1550 if(!close_event_func(event_handle)) {
1551 infof(data, "WSACloseEvent failed (%d)", SOCKERRNO);
1552 }
1553
1554 /* "Forget" pointers into the library we're about to free */
1555 create_event_func = NULL;
1556 close_event_func = NULL;
1557 event_select_func = NULL;
1558 enum_netevents_func = NULL;
1559
1560 /* We called LoadLibrary, so call FreeLibrary */
1561 if(!FreeLibrary(wsock2))
1562 infof(data, "FreeLibrary(wsock2) failed (%d)", ERRNO);
1563 #else
1564 pfd[0].fd = sockfd;
1565 pfd[0].events = POLLIN;
1566
1567 if(data->set.is_fread_set) {
1568 poll_cnt = 1;
1569 interval_ms = 100; /* poll user-supplied read function */
1570 }
1571 else {
1572 /* really using fread, so infile is a FILE* */
1573 pfd[1].fd = fileno((FILE *)data->state.in);
1574 pfd[1].events = POLLIN;
1575 poll_cnt = 2;
1576 interval_ms = 1 * 1000;
1577 }
1578
1579 while(keepon) {
1580 switch (Curl_poll(pfd, poll_cnt, interval_ms)) {
1581 case -1: /* error, stop reading */
1582 keepon = FALSE;
1583 continue;
1584 case 0: /* timeout */
1585 pfd[0].revents = 0;
1586 pfd[1].revents = 0;
1587 /* fall through */
1588 default: /* read! */
1589 if(pfd[0].revents & POLLIN) {
1590 /* read data from network */
1591 result = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
1592 /* read would've blocked. Loop again */
1593 if(result == CURLE_AGAIN)
1594 break;
1595 /* returned not-zero, this an error */
1596 else if(result) {
1597 keepon = FALSE;
1598 break;
1599 }
1600 /* returned zero but actually received 0 or less here,
1601 the server closed the connection and we bail out */
1602 else if(nread <= 0) {
1603 keepon = FALSE;
1604 break;
1605 }
1606
1607 total_dl += nread;
1608 Curl_pgrsSetDownloadCounter(data, total_dl);
1609 result = telrcv(conn, (unsigned char *)buf, nread);
1610 if(result) {
1611 keepon = FALSE;
1612 break;
1613 }
1614
1615 /* Negotiate if the peer has started negotiating,
1616 otherwise don't. We don't want to speak telnet with
1617 non-telnet servers, like POP or SMTP. */
1618 if(tn->please_negotiate && !tn->already_negotiated) {
1619 negotiate(conn);
1620 tn->already_negotiated = 1;
1621 }
1622 }
1623
1624 nread = 0;
1625 if(poll_cnt == 2) {
1626 if(pfd[1].revents & POLLIN) { /* read from in file */
1627 nread = read(pfd[1].fd, buf, BUFSIZE - 1);
1628 }
1629 }
1630 else {
1631 /* read from user-supplied method */
1632 nread = (int)data->state.fread_func(buf, 1, BUFSIZE - 1,
1633 data->state.in);
1634 if(nread == CURL_READFUNC_ABORT) {
1635 keepon = FALSE;
1636 break;
1637 }
1638 if(nread == CURL_READFUNC_PAUSE)
1639 break;
1640 }
1641
1642 if(nread > 0) {
1643 result = send_telnet_data(conn, buf, nread);
1644 if(result) {
1645 keepon = FALSE;
1646 break;
1647 }
1648 total_ul += nread;
1649 Curl_pgrsSetUploadCounter(data, total_ul);
1650 }
1651 else if(nread < 0)
1652 keepon = FALSE;
1653
1654 break;
1655 } /* poll switch statement */
1656
1657 if(data->set.timeout) {
1658 now = Curl_tvnow();
1659 if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
1660 failf(data, "Time-out");
1661 result = CURLE_OPERATION_TIMEDOUT;
1662 keepon = FALSE;
1663 }
1664 }
1665
1666 if(Curl_pgrsUpdate(conn)) {
1667 result = CURLE_ABORTED_BY_CALLBACK;
1668 break;
1669 }
1670 }
1671 #endif
1672 /* mark this as "no further transfer wanted" */
1673 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1674
1675 return result;
1676 }
1677 #endif
1678