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