telnet.c (45756B)
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 "url.h" 51 #include <curl/curl.h> 52 #include "transfer.h" 53 #include "sendf.h" 54 #include "telnet.h" 55 #include "connect.h" 56 #include "progress.h" 57 #include "system_win32.h" 58 #include "arpa_telnet.h" 59 #include "select.h" 60 #include "curlx/warnless.h" 61 #include "curlx/strparse.h" 62 63 /* The last 3 #include files should be in this order */ 64 #include "curl_printf.h" 65 #include "curl_memory.h" 66 #include "memdebug.h" 67 68 #define SUBBUFSIZE 512 69 70 #define CURL_SB_CLEAR(x) x->subpointer = x->subbuffer 71 #define CURL_SB_TERM(x) \ 72 do { \ 73 x->subend = x->subpointer; \ 74 CURL_SB_CLEAR(x); \ 75 } while(0) 76 #define CURL_SB_ACCUM(x,c) \ 77 do { \ 78 if(x->subpointer < (x->subbuffer + sizeof(x->subbuffer))) \ 79 *x->subpointer++ = (c); \ 80 } while(0) 81 82 #define CURL_SB_GET(x) ((*x->subpointer++)&0xff) 83 #define CURL_SB_LEN(x) (x->subend - x->subpointer) 84 85 /* For posterity: 86 #define CURL_SB_PEEK(x) ((*x->subpointer)&0xff) 87 #define CURL_SB_EOF(x) (x->subpointer >= x->subend) */ 88 89 #ifdef CURL_DISABLE_VERBOSE_STRINGS 90 #define printoption(a,b,c,d) Curl_nop_stmt 91 #endif 92 93 /* For negotiation compliant to RFC 1143 */ 94 #define CURL_NO 0 95 #define CURL_YES 1 96 #define CURL_WANTYES 2 97 #define CURL_WANTNO 3 98 99 #define CURL_EMPTY 0 100 #define CURL_OPPOSITE 1 101 102 103 /* meta key for storing protocol meta at easy handle */ 104 #define CURL_META_TELNET_EASY "meta:proto:telnet:easy" 105 106 /* 107 * Telnet receiver states for fsm 108 */ 109 typedef enum 110 { 111 CURL_TS_DATA = 0, 112 CURL_TS_IAC, 113 CURL_TS_WILL, 114 CURL_TS_WONT, 115 CURL_TS_DO, 116 CURL_TS_DONT, 117 CURL_TS_CR, 118 CURL_TS_SB, /* sub-option collection */ 119 CURL_TS_SE /* looking for sub-option end */ 120 } TelnetReceive; 121 122 struct TELNET { 123 int please_negotiate; 124 int already_negotiated; 125 int us[256]; 126 int usq[256]; 127 int us_preferred[256]; 128 int him[256]; 129 int himq[256]; 130 int him_preferred[256]; 131 int subnegotiation[256]; 132 char *subopt_ttype; /* Set with suboption TTYPE */ 133 char *subopt_xdisploc; /* Set with suboption XDISPLOC */ 134 unsigned short subopt_wsx; /* Set with suboption NAWS */ 135 unsigned short subopt_wsy; /* Set with suboption NAWS */ 136 TelnetReceive telrcv_state; 137 struct curl_slist *telnet_vars; /* Environment variables */ 138 struct dynbuf out; /* output buffer */ 139 140 /* suboptions */ 141 unsigned char subbuffer[SUBBUFSIZE]; 142 unsigned char *subpointer, *subend; /* buffer for sub-options */ 143 }; 144 145 146 static 147 CURLcode telrcv(struct Curl_easy *data, 148 struct TELNET *tn, 149 const unsigned char *inbuf, /* Data received from socket */ 150 ssize_t count); /* Number of bytes received */ 151 152 #ifndef CURL_DISABLE_VERBOSE_STRINGS 153 static void printoption(struct Curl_easy *data, 154 const char *direction, 155 int cmd, int option); 156 #endif 157 158 static void send_negotiation(struct Curl_easy *data, int cmd, int option); 159 static void set_local_option(struct Curl_easy *data, struct TELNET *tn, 160 int option, int newstate); 161 static void set_remote_option(struct Curl_easy *data, struct TELNET *tn, 162 int option, int newstate); 163 164 static void printsub(struct Curl_easy *data, 165 int direction, unsigned char *pointer, 166 size_t length); 167 static void suboption(struct Curl_easy *data, struct TELNET *tn); 168 static void sendsuboption(struct Curl_easy *data, 169 struct TELNET *tn, int option); 170 171 static CURLcode telnet_do(struct Curl_easy *data, bool *done); 172 static CURLcode telnet_done(struct Curl_easy *data, 173 CURLcode, bool premature); 174 static CURLcode send_telnet_data(struct Curl_easy *data, 175 struct TELNET *tn, 176 char *buffer, ssize_t nread); 177 178 /* 179 * TELNET protocol handler. 180 */ 181 182 const struct Curl_handler Curl_handler_telnet = { 183 "telnet", /* scheme */ 184 ZERO_NULL, /* setup_connection */ 185 telnet_do, /* do_it */ 186 telnet_done, /* done */ 187 ZERO_NULL, /* do_more */ 188 ZERO_NULL, /* connect_it */ 189 ZERO_NULL, /* connecting */ 190 ZERO_NULL, /* doing */ 191 ZERO_NULL, /* proto_getsock */ 192 ZERO_NULL, /* doing_getsock */ 193 ZERO_NULL, /* domore_getsock */ 194 ZERO_NULL, /* perform_getsock */ 195 ZERO_NULL, /* disconnect */ 196 ZERO_NULL, /* write_resp */ 197 ZERO_NULL, /* write_resp_hd */ 198 ZERO_NULL, /* connection_check */ 199 ZERO_NULL, /* attach connection */ 200 ZERO_NULL, /* follow */ 201 PORT_TELNET, /* defport */ 202 CURLPROTO_TELNET, /* protocol */ 203 CURLPROTO_TELNET, /* family */ 204 PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */ 205 }; 206 207 208 static void telnet_easy_dtor(void *key, size_t klen, void *entry) 209 { 210 struct TELNET *tn = entry; 211 (void)key; 212 (void)klen; 213 curl_slist_free_all(tn->telnet_vars); 214 curlx_dyn_free(&tn->out); 215 free(tn); 216 } 217 218 static 219 CURLcode init_telnet(struct Curl_easy *data) 220 { 221 struct TELNET *tn; 222 223 tn = calloc(1, sizeof(struct TELNET)); 224 if(!tn) 225 return CURLE_OUT_OF_MEMORY; 226 227 curlx_dyn_init(&tn->out, 0xffff); 228 229 tn->telrcv_state = CURL_TS_DATA; 230 231 /* Init suboptions */ 232 CURL_SB_CLEAR(tn); 233 234 /* Set the options we want by default */ 235 tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES; 236 tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES; 237 238 /* To be compliant with previous releases of libcurl 239 we enable this option by default. This behavior 240 can be changed thanks to the "BINARY" option in 241 CURLOPT_TELNETOPTIONS 242 */ 243 tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES; 244 tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES; 245 246 /* We must allow the server to echo what we sent 247 but it is not necessary to request the server 248 to do so (it might forces the server to close 249 the connection). Hence, we ignore ECHO in the 250 negotiate function 251 */ 252 tn->him_preferred[CURL_TELOPT_ECHO] = CURL_YES; 253 254 /* Set the subnegotiation fields to send information 255 just after negotiation passed (do/will) 256 257 Default values are (0,0) initialized by calloc. 258 According to the RFC1013 it is valid: 259 A value equal to zero is acceptable for the width (or height), 260 and means that no character width (or height) is being sent. 261 In this case, the width (or height) that will be assumed by the 262 Telnet server is operating system specific (it will probably be 263 based upon the terminal type information that may have been sent 264 using the TERMINAL TYPE Telnet option). */ 265 tn->subnegotiation[CURL_TELOPT_NAWS] = CURL_YES; 266 267 return Curl_meta_set(data, CURL_META_TELNET_EASY, tn, telnet_easy_dtor); 268 } 269 270 static void telnet_negotiate(struct Curl_easy *data, struct TELNET *tn) 271 { 272 int i; 273 274 for(i = 0; i < CURL_NTELOPTS; i++) { 275 if(i == CURL_TELOPT_ECHO) 276 continue; 277 278 if(tn->us_preferred[i] == CURL_YES) 279 set_local_option(data, tn, i, CURL_YES); 280 281 if(tn->him_preferred[i] == CURL_YES) 282 set_remote_option(data, tn, i, CURL_YES); 283 } 284 } 285 286 #ifndef CURL_DISABLE_VERBOSE_STRINGS 287 static void printoption(struct Curl_easy *data, 288 const char *direction, int cmd, int option) 289 { 290 if(data->set.verbose) { 291 if(cmd == CURL_IAC) { 292 if(CURL_TELCMD_OK(option)) 293 infof(data, "%s IAC %s", direction, CURL_TELCMD(option)); 294 else 295 infof(data, "%s IAC %d", direction, option); 296 } 297 else { 298 const char *fmt = (cmd == CURL_WILL) ? "WILL" : 299 (cmd == CURL_WONT) ? "WONT" : 300 (cmd == CURL_DO) ? "DO" : 301 (cmd == CURL_DONT) ? "DONT" : 0; 302 if(fmt) { 303 const char *opt; 304 if(CURL_TELOPT_OK(option)) 305 opt = CURL_TELOPT(option); 306 else if(option == CURL_TELOPT_EXOPL) 307 opt = "EXOPL"; 308 else 309 opt = NULL; 310 311 if(opt) 312 infof(data, "%s %s %s", direction, fmt, opt); 313 else 314 infof(data, "%s %s %d", direction, fmt, option); 315 } 316 else 317 infof(data, "%s %d %d", direction, cmd, option); 318 } 319 } 320 } 321 #endif 322 323 static void send_negotiation(struct Curl_easy *data, int cmd, int option) 324 { 325 unsigned char buf[3]; 326 ssize_t bytes_written; 327 struct connectdata *conn = data->conn; 328 329 buf[0] = CURL_IAC; 330 buf[1] = (unsigned char)cmd; 331 buf[2] = (unsigned char)option; 332 333 bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3); 334 if(bytes_written < 0) { 335 int err = SOCKERRNO; 336 failf(data,"Sending data failed (%d)",err); 337 } 338 339 printoption(data, "SENT", cmd, option); 340 } 341 342 static 343 void set_remote_option(struct Curl_easy *data, struct TELNET *tn, 344 int option, int newstate) 345 { 346 if(newstate == CURL_YES) { 347 switch(tn->him[option]) { 348 case CURL_NO: 349 tn->him[option] = CURL_WANTYES; 350 send_negotiation(data, CURL_DO, option); 351 break; 352 353 case CURL_YES: 354 /* Already enabled */ 355 break; 356 357 case CURL_WANTNO: 358 switch(tn->himq[option]) { 359 case CURL_EMPTY: 360 /* Already negotiating for CURL_YES, queue the request */ 361 tn->himq[option] = CURL_OPPOSITE; 362 break; 363 case CURL_OPPOSITE: 364 /* Error: already queued an enable request */ 365 break; 366 } 367 break; 368 369 case CURL_WANTYES: 370 switch(tn->himq[option]) { 371 case CURL_EMPTY: 372 /* Error: already negotiating for enable */ 373 break; 374 case CURL_OPPOSITE: 375 tn->himq[option] = CURL_EMPTY; 376 break; 377 } 378 break; 379 } 380 } 381 else { /* NO */ 382 switch(tn->him[option]) { 383 case CURL_NO: 384 /* Already disabled */ 385 break; 386 387 case CURL_YES: 388 tn->him[option] = CURL_WANTNO; 389 send_negotiation(data, CURL_DONT, option); 390 break; 391 392 case CURL_WANTNO: 393 switch(tn->himq[option]) { 394 case CURL_EMPTY: 395 /* Already negotiating for NO */ 396 break; 397 case CURL_OPPOSITE: 398 tn->himq[option] = CURL_EMPTY; 399 break; 400 } 401 break; 402 403 case CURL_WANTYES: 404 switch(tn->himq[option]) { 405 case CURL_EMPTY: 406 tn->himq[option] = CURL_OPPOSITE; 407 break; 408 case CURL_OPPOSITE: 409 break; 410 } 411 break; 412 } 413 } 414 } 415 416 static 417 void rec_will(struct Curl_easy *data, struct TELNET *tn, int option) 418 { 419 switch(tn->him[option]) { 420 case CURL_NO: 421 if(tn->him_preferred[option] == CURL_YES) { 422 tn->him[option] = CURL_YES; 423 send_negotiation(data, CURL_DO, option); 424 } 425 else 426 send_negotiation(data, CURL_DONT, option); 427 428 break; 429 430 case CURL_YES: 431 /* Already enabled */ 432 break; 433 434 case CURL_WANTNO: 435 switch(tn->himq[option]) { 436 case CURL_EMPTY: 437 /* Error: DONT answered by WILL */ 438 tn->him[option] = CURL_NO; 439 break; 440 case CURL_OPPOSITE: 441 /* Error: DONT answered by WILL */ 442 tn->him[option] = CURL_YES; 443 tn->himq[option] = CURL_EMPTY; 444 break; 445 } 446 break; 447 448 case CURL_WANTYES: 449 switch(tn->himq[option]) { 450 case CURL_EMPTY: 451 tn->him[option] = CURL_YES; 452 break; 453 case CURL_OPPOSITE: 454 tn->him[option] = CURL_WANTNO; 455 tn->himq[option] = CURL_EMPTY; 456 send_negotiation(data, CURL_DONT, option); 457 break; 458 } 459 break; 460 } 461 } 462 463 static 464 void rec_wont(struct Curl_easy *data, struct TELNET *tn, int option) 465 { 466 switch(tn->him[option]) { 467 case CURL_NO: 468 /* Already disabled */ 469 break; 470 471 case CURL_YES: 472 tn->him[option] = CURL_NO; 473 send_negotiation(data, CURL_DONT, option); 474 break; 475 476 case CURL_WANTNO: 477 switch(tn->himq[option]) { 478 case CURL_EMPTY: 479 tn->him[option] = CURL_NO; 480 break; 481 482 case CURL_OPPOSITE: 483 tn->him[option] = CURL_WANTYES; 484 tn->himq[option] = CURL_EMPTY; 485 send_negotiation(data, CURL_DO, option); 486 break; 487 } 488 break; 489 490 case CURL_WANTYES: 491 switch(tn->himq[option]) { 492 case CURL_EMPTY: 493 tn->him[option] = CURL_NO; 494 break; 495 case CURL_OPPOSITE: 496 tn->him[option] = CURL_NO; 497 tn->himq[option] = CURL_EMPTY; 498 break; 499 } 500 break; 501 } 502 } 503 504 static void 505 set_local_option(struct Curl_easy *data, struct TELNET *tn, 506 int option, int newstate) 507 { 508 if(newstate == CURL_YES) { 509 switch(tn->us[option]) { 510 case CURL_NO: 511 tn->us[option] = CURL_WANTYES; 512 send_negotiation(data, CURL_WILL, option); 513 break; 514 515 case CURL_YES: 516 /* Already enabled */ 517 break; 518 519 case CURL_WANTNO: 520 switch(tn->usq[option]) { 521 case CURL_EMPTY: 522 /* Already negotiating for CURL_YES, queue the request */ 523 tn->usq[option] = CURL_OPPOSITE; 524 break; 525 case CURL_OPPOSITE: 526 /* Error: already queued an enable request */ 527 break; 528 } 529 break; 530 531 case CURL_WANTYES: 532 switch(tn->usq[option]) { 533 case CURL_EMPTY: 534 /* Error: already negotiating for enable */ 535 break; 536 case CURL_OPPOSITE: 537 tn->usq[option] = CURL_EMPTY; 538 break; 539 } 540 break; 541 } 542 } 543 else { /* NO */ 544 switch(tn->us[option]) { 545 case CURL_NO: 546 /* Already disabled */ 547 break; 548 549 case CURL_YES: 550 tn->us[option] = CURL_WANTNO; 551 send_negotiation(data, CURL_WONT, option); 552 break; 553 554 case CURL_WANTNO: 555 switch(tn->usq[option]) { 556 case CURL_EMPTY: 557 /* Already negotiating for NO */ 558 break; 559 case CURL_OPPOSITE: 560 tn->usq[option] = CURL_EMPTY; 561 break; 562 } 563 break; 564 565 case CURL_WANTYES: 566 switch(tn->usq[option]) { 567 case CURL_EMPTY: 568 tn->usq[option] = CURL_OPPOSITE; 569 break; 570 case CURL_OPPOSITE: 571 break; 572 } 573 break; 574 } 575 } 576 } 577 578 static 579 void rec_do(struct Curl_easy *data, struct TELNET *tn, int option) 580 { 581 switch(tn->us[option]) { 582 case CURL_NO: 583 if(tn->us_preferred[option] == CURL_YES) { 584 tn->us[option] = CURL_YES; 585 send_negotiation(data, CURL_WILL, option); 586 if(tn->subnegotiation[option] == CURL_YES) 587 /* transmission of data option */ 588 sendsuboption(data, tn, option); 589 } 590 else if(tn->subnegotiation[option] == CURL_YES) { 591 /* send information to achieve this option */ 592 tn->us[option] = CURL_YES; 593 send_negotiation(data, CURL_WILL, option); 594 sendsuboption(data, tn, option); 595 } 596 else 597 send_negotiation(data, CURL_WONT, option); 598 break; 599 600 case CURL_YES: 601 /* Already enabled */ 602 break; 603 604 case CURL_WANTNO: 605 switch(tn->usq[option]) { 606 case CURL_EMPTY: 607 /* Error: DONT answered by WILL */ 608 tn->us[option] = CURL_NO; 609 break; 610 case CURL_OPPOSITE: 611 /* Error: DONT answered by WILL */ 612 tn->us[option] = CURL_YES; 613 tn->usq[option] = CURL_EMPTY; 614 break; 615 } 616 break; 617 618 case CURL_WANTYES: 619 switch(tn->usq[option]) { 620 case CURL_EMPTY: 621 tn->us[option] = CURL_YES; 622 if(tn->subnegotiation[option] == CURL_YES) { 623 /* transmission of data option */ 624 sendsuboption(data, tn, option); 625 } 626 break; 627 case CURL_OPPOSITE: 628 tn->us[option] = CURL_WANTNO; 629 tn->himq[option] = CURL_EMPTY; 630 send_negotiation(data, CURL_WONT, option); 631 break; 632 } 633 break; 634 } 635 } 636 637 static 638 void rec_dont(struct Curl_easy *data, struct TELNET *tn, int option) 639 { 640 switch(tn->us[option]) { 641 case CURL_NO: 642 /* Already disabled */ 643 break; 644 645 case CURL_YES: 646 tn->us[option] = CURL_NO; 647 send_negotiation(data, CURL_WONT, option); 648 break; 649 650 case CURL_WANTNO: 651 switch(tn->usq[option]) { 652 case CURL_EMPTY: 653 tn->us[option] = CURL_NO; 654 break; 655 656 case CURL_OPPOSITE: 657 tn->us[option] = CURL_WANTYES; 658 tn->usq[option] = CURL_EMPTY; 659 send_negotiation(data, CURL_WILL, option); 660 break; 661 } 662 break; 663 664 case CURL_WANTYES: 665 switch(tn->usq[option]) { 666 case CURL_EMPTY: 667 tn->us[option] = CURL_NO; 668 break; 669 case CURL_OPPOSITE: 670 tn->us[option] = CURL_NO; 671 tn->usq[option] = CURL_EMPTY; 672 break; 673 } 674 break; 675 } 676 } 677 678 679 static void printsub(struct Curl_easy *data, 680 int direction, /* '<' or '>' */ 681 unsigned char *pointer, /* where suboption data is */ 682 size_t length) /* length of suboption data */ 683 { 684 if(data->set.verbose) { 685 unsigned int i = 0; 686 if(direction) { 687 infof(data, "%s IAC SB ", (direction == '<') ? "RCVD" : "SENT"); 688 if(length >= 3) { 689 int j; 690 691 i = pointer[length-2]; 692 j = pointer[length-1]; 693 694 if(i != CURL_IAC || j != CURL_SE) { 695 infof(data, "(terminated by "); 696 if(CURL_TELOPT_OK(i)) 697 infof(data, "%s ", CURL_TELOPT(i)); 698 else if(CURL_TELCMD_OK(i)) 699 infof(data, "%s ", CURL_TELCMD(i)); 700 else 701 infof(data, "%u ", i); 702 if(CURL_TELOPT_OK(j)) 703 infof(data, "%s", CURL_TELOPT(j)); 704 else if(CURL_TELCMD_OK(j)) 705 infof(data, "%s", CURL_TELCMD(j)); 706 else 707 infof(data, "%d", j); 708 infof(data, ", not IAC SE) "); 709 } 710 } 711 if(length >= 2) 712 length -= 2; 713 else /* bad input */ 714 return; 715 } 716 if(length < 1) { 717 infof(data, "(Empty suboption?)"); 718 return; 719 } 720 721 if(CURL_TELOPT_OK(pointer[0])) { 722 switch(pointer[0]) { 723 case CURL_TELOPT_TTYPE: 724 case CURL_TELOPT_XDISPLOC: 725 case CURL_TELOPT_NEW_ENVIRON: 726 case CURL_TELOPT_NAWS: 727 infof(data, "%s", CURL_TELOPT(pointer[0])); 728 break; 729 default: 730 infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0])); 731 break; 732 } 733 } 734 else 735 infof(data, "%d (unknown)", pointer[i]); 736 737 switch(pointer[0]) { 738 case CURL_TELOPT_NAWS: 739 if(length > 4) 740 infof(data, "Width: %d ; Height: %d", (pointer[1] << 8) | pointer[2], 741 (pointer[3] << 8) | pointer[4]); 742 break; 743 default: 744 switch(pointer[1]) { 745 case CURL_TELQUAL_IS: 746 infof(data, " IS"); 747 break; 748 case CURL_TELQUAL_SEND: 749 infof(data, " SEND"); 750 break; 751 case CURL_TELQUAL_INFO: 752 infof(data, " INFO/REPLY"); 753 break; 754 case CURL_TELQUAL_NAME: 755 infof(data, " NAME"); 756 break; 757 } 758 759 switch(pointer[0]) { 760 case CURL_TELOPT_TTYPE: 761 case CURL_TELOPT_XDISPLOC: 762 pointer[length] = 0; 763 infof(data, " \"%s\"", &pointer[2]); 764 break; 765 case CURL_TELOPT_NEW_ENVIRON: 766 if(pointer[1] == CURL_TELQUAL_IS) { 767 infof(data, " "); 768 for(i = 3; i < length; i++) { 769 switch(pointer[i]) { 770 case CURL_NEW_ENV_VAR: 771 infof(data, ", "); 772 break; 773 case CURL_NEW_ENV_VALUE: 774 infof(data, " = "); 775 break; 776 default: 777 infof(data, "%c", pointer[i]); 778 break; 779 } 780 } 781 } 782 break; 783 default: 784 for(i = 2; i < length; i++) 785 infof(data, " %.2x", pointer[i]); 786 break; 787 } 788 } 789 } 790 } 791 792 static bool str_is_nonascii(const char *str) 793 { 794 char c; 795 while((c = *str++) != 0) 796 if(c & 0x80) 797 return TRUE; 798 799 return FALSE; 800 } 801 802 static CURLcode check_telnet_options(struct Curl_easy *data, 803 struct TELNET *tn) 804 { 805 struct curl_slist *head; 806 struct curl_slist *beg; 807 CURLcode result = CURLE_OK; 808 809 /* Add the username as an environment variable if it 810 was given on the command line */ 811 if(data->state.aptr.user) { 812 char buffer[256]; 813 if(str_is_nonascii(data->conn->user)) { 814 DEBUGF(infof(data, "set a non ASCII username in telnet")); 815 return CURLE_BAD_FUNCTION_ARGUMENT; 816 } 817 msnprintf(buffer, sizeof(buffer), "USER,%s", data->conn->user); 818 beg = curl_slist_append(tn->telnet_vars, buffer); 819 if(!beg) { 820 curl_slist_free_all(tn->telnet_vars); 821 tn->telnet_vars = NULL; 822 return CURLE_OUT_OF_MEMORY; 823 } 824 tn->telnet_vars = beg; 825 tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES; 826 } 827 828 for(head = data->set.telnet_options; head && !result; head = head->next) { 829 size_t olen; 830 char *option = head->data; 831 char *arg; 832 char *sep = strchr(option, '='); 833 if(sep) { 834 olen = sep - option; 835 arg = ++sep; 836 if(str_is_nonascii(arg)) 837 continue; 838 switch(olen) { 839 case 5: 840 /* Terminal type */ 841 if(curl_strnequal(option, "TTYPE", 5)) { 842 tn->subopt_ttype = arg; 843 tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES; 844 break; 845 } 846 result = CURLE_UNKNOWN_OPTION; 847 break; 848 849 case 8: 850 /* Display variable */ 851 if(curl_strnequal(option, "XDISPLOC", 8)) { 852 tn->subopt_xdisploc = arg; 853 tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES; 854 break; 855 } 856 result = CURLE_UNKNOWN_OPTION; 857 break; 858 859 case 7: 860 /* Environment variable */ 861 if(curl_strnequal(option, "NEW_ENV", 7)) { 862 beg = curl_slist_append(tn->telnet_vars, arg); 863 if(!beg) { 864 result = CURLE_OUT_OF_MEMORY; 865 break; 866 } 867 tn->telnet_vars = beg; 868 tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES; 869 } 870 else 871 result = CURLE_UNKNOWN_OPTION; 872 break; 873 874 case 2: 875 /* Window Size */ 876 if(curl_strnequal(option, "WS", 2)) { 877 const char *p = arg; 878 curl_off_t x = 0; 879 curl_off_t y = 0; 880 if(curlx_str_number(&p, &x, 0xffff) || 881 curlx_str_single(&p, 'x') || 882 curlx_str_number(&p, &y, 0xffff)) { 883 failf(data, "Syntax error in telnet option: %s", head->data); 884 result = CURLE_SETOPT_OPTION_SYNTAX; 885 } 886 else { 887 tn->subopt_wsx = (unsigned short)x; 888 tn->subopt_wsy = (unsigned short)y; 889 tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES; 890 } 891 } 892 else 893 result = CURLE_UNKNOWN_OPTION; 894 break; 895 896 case 6: 897 /* To take care or not of the 8th bit in data exchange */ 898 if(curl_strnequal(option, "BINARY", 6)) { 899 int binary_option = atoi(arg); 900 if(binary_option != 1) { 901 tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO; 902 tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO; 903 } 904 } 905 else 906 result = CURLE_UNKNOWN_OPTION; 907 break; 908 default: 909 failf(data, "Unknown telnet option %s", head->data); 910 result = CURLE_UNKNOWN_OPTION; 911 break; 912 } 913 } 914 else { 915 failf(data, "Syntax error in telnet option: %s", head->data); 916 result = CURLE_SETOPT_OPTION_SYNTAX; 917 } 918 } 919 920 if(result) { 921 curl_slist_free_all(tn->telnet_vars); 922 tn->telnet_vars = NULL; 923 } 924 925 return result; 926 } 927 928 /* 929 * suboption() 930 * 931 * Look at the sub-option buffer, and try to be helpful to the other 932 * side. 933 */ 934 935 static void suboption(struct Curl_easy *data, struct TELNET *tn) 936 { 937 struct curl_slist *v; 938 unsigned char temp[2048]; 939 ssize_t bytes_written; 940 size_t len; 941 int err; 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 1013 static void sendsuboption(struct Curl_easy *data, 1014 struct TELNET *tn, int option) 1015 { 1016 ssize_t bytes_written; 1017 int err; 1018 unsigned short x, y; 1019 unsigned char *uc1, *uc2; 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, tn, (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 1068 static 1069 CURLcode telrcv(struct Curl_easy *data, 1070 struct TELNET *tn, 1071 const unsigned char *inbuf, /* Data received from socket */ 1072 ssize_t count) /* Number of bytes received */ 1073 { 1074 unsigned char c; 1075 CURLcode result; 1076 int in = 0; 1077 int startwrite = -1; 1078 1079 #define startskipping() \ 1080 if(startwrite >= 0) { \ 1081 result = Curl_client_write(data, \ 1082 CLIENTWRITE_BODY, \ 1083 (const 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: 1121 process_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, tn, 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, tn, 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, tn, 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, tn, 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, tn); /* 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, tn); /* 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 */ 1231 static CURLcode send_telnet_data(struct Curl_easy *data, 1232 struct TELNET *tn, 1233 char *buffer, ssize_t nread) 1234 { 1235 size_t i, outlen; 1236 unsigned char *outbuf; 1237 CURLcode result = CURLE_OK; 1238 size_t bytes_written; 1239 size_t total_written = 0; 1240 struct connectdata *conn = data->conn; 1241 1242 DEBUGASSERT(tn); 1243 DEBUGASSERT(nread > 0); 1244 if(nread < 0) 1245 return CURLE_TOO_LARGE; 1246 1247 if(memchr(buffer, CURL_IAC, nread)) { 1248 /* only use the escape buffer when necessary */ 1249 curlx_dyn_reset(&tn->out); 1250 1251 for(i = 0; i < (size_t)nread && !result; i++) { 1252 result = curlx_dyn_addn(&tn->out, &buffer[i], 1); 1253 if(!result && ((unsigned char)buffer[i] == CURL_IAC)) 1254 /* IAC is FF in hex */ 1255 result = curlx_dyn_addn(&tn->out, "\xff", 1); 1256 } 1257 1258 outlen = curlx_dyn_len(&tn->out); 1259 outbuf = curlx_dyn_uptr(&tn->out); 1260 } 1261 else { 1262 outlen = (size_t)nread; 1263 outbuf = (unsigned char *)buffer; 1264 } 1265 while(!result && total_written < outlen) { 1266 /* Make sure socket is writable to avoid EWOULDBLOCK condition */ 1267 struct pollfd pfd[1]; 1268 pfd[0].fd = conn->sock[FIRSTSOCKET]; 1269 pfd[0].events = POLLOUT; 1270 switch(Curl_poll(pfd, 1, -1)) { 1271 case -1: /* error, abort writing */ 1272 case 0: /* timeout (will never happen) */ 1273 result = CURLE_SEND_ERROR; 1274 break; 1275 default: /* write! */ 1276 bytes_written = 0; 1277 result = Curl_xfer_send(data, outbuf + total_written, 1278 outlen - total_written, FALSE, &bytes_written); 1279 total_written += bytes_written; 1280 break; 1281 } 1282 } 1283 1284 return result; 1285 } 1286 1287 static CURLcode telnet_done(struct Curl_easy *data, 1288 CURLcode status, bool premature) 1289 { 1290 (void)status; /* unused */ 1291 (void)premature; /* not used */ 1292 Curl_meta_remove(data, CURL_META_TELNET_EASY); 1293 return CURLE_OK; 1294 } 1295 1296 static CURLcode telnet_do(struct Curl_easy *data, bool *done) 1297 { 1298 CURLcode result; 1299 struct connectdata *conn = data->conn; 1300 curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; 1301 #ifdef USE_WINSOCK 1302 WSAEVENT event_handle; 1303 WSANETWORKEVENTS events; 1304 HANDLE stdin_handle; 1305 HANDLE objs[2]; 1306 DWORD obj_count; 1307 DWORD wait_timeout; 1308 DWORD readfile_read; 1309 int err; 1310 #else 1311 timediff_t interval_ms; 1312 struct pollfd pfd[2]; 1313 int poll_cnt; 1314 curl_off_t total_dl = 0; 1315 curl_off_t total_ul = 0; 1316 ssize_t snread; 1317 #endif 1318 struct curltime now; 1319 bool keepon = TRUE; 1320 char buffer[4*1024]; 1321 struct TELNET *tn; 1322 1323 *done = TRUE; /* unconditionally */ 1324 1325 result = init_telnet(data); 1326 if(result) 1327 return result; 1328 1329 tn = Curl_meta_get(data, CURL_META_TELNET_EASY); 1330 if(!tn) 1331 return CURLE_FAILED_INIT; 1332 1333 result = check_telnet_options(data, tn); 1334 if(result) 1335 return result; 1336 1337 #ifdef USE_WINSOCK 1338 /* We want to wait for both stdin and the socket. Since 1339 ** the select() function in Winsock only works on sockets 1340 ** we have to use the WaitForMultipleObjects() call. 1341 */ 1342 1343 /* First, create a sockets event object */ 1344 event_handle = WSACreateEvent(); 1345 if(event_handle == WSA_INVALID_EVENT) { 1346 failf(data, "WSACreateEvent failed (%d)", SOCKERRNO); 1347 return CURLE_FAILED_INIT; 1348 } 1349 1350 /* Tell Winsock what events we want to listen to */ 1351 if(WSAEventSelect(sockfd, event_handle, FD_READ|FD_CLOSE) == SOCKET_ERROR) { 1352 WSACloseEvent(event_handle); 1353 return CURLE_OK; 1354 } 1355 1356 /* The get the Windows file handle for stdin */ 1357 stdin_handle = GetStdHandle(STD_INPUT_HANDLE); 1358 1359 /* Create the list of objects to wait for */ 1360 objs[0] = event_handle; 1361 objs[1] = stdin_handle; 1362 1363 /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it, 1364 else use the old WaitForMultipleObjects() way */ 1365 if(GetFileType(stdin_handle) == FILE_TYPE_PIPE || 1366 data->set.is_fread_set) { 1367 /* Do not wait for stdin_handle, just wait for event_handle */ 1368 obj_count = 1; 1369 /* Check stdin_handle per 100 milliseconds */ 1370 wait_timeout = 100; 1371 } 1372 else { 1373 obj_count = 2; 1374 wait_timeout = 1000; 1375 } 1376 1377 /* Keep on listening and act on events */ 1378 while(keepon) { 1379 const DWORD buf_size = (DWORD)sizeof(buffer); 1380 DWORD waitret = WaitForMultipleObjects(obj_count, objs, 1381 FALSE, wait_timeout); 1382 switch(waitret) { 1383 1384 case WAIT_TIMEOUT: 1385 { 1386 for(;;) { 1387 if(data->set.is_fread_set) { 1388 size_t n; 1389 /* read from user-supplied method */ 1390 n = data->state.fread_func(buffer, 1, buf_size, data->state.in); 1391 if(n == CURL_READFUNC_ABORT) { 1392 keepon = FALSE; 1393 result = CURLE_READ_ERROR; 1394 break; 1395 } 1396 1397 if(n == CURL_READFUNC_PAUSE) 1398 break; 1399 1400 if(n == 0) /* no bytes */ 1401 break; 1402 1403 /* fall through with number of bytes read */ 1404 readfile_read = (DWORD)n; 1405 } 1406 else { 1407 /* read from stdin */ 1408 if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, 1409 &readfile_read, NULL)) { 1410 keepon = FALSE; 1411 result = CURLE_READ_ERROR; 1412 break; 1413 } 1414 1415 if(!readfile_read) 1416 break; 1417 1418 if(!ReadFile(stdin_handle, buffer, buf_size, 1419 &readfile_read, NULL)) { 1420 keepon = FALSE; 1421 result = CURLE_READ_ERROR; 1422 break; 1423 } 1424 } 1425 1426 result = send_telnet_data(data, tn, buffer, readfile_read); 1427 if(result) { 1428 keepon = FALSE; 1429 break; 1430 } 1431 } 1432 } 1433 break; 1434 1435 case WAIT_OBJECT_0 + 1: 1436 { 1437 if(!ReadFile(stdin_handle, buffer, buf_size, 1438 &readfile_read, NULL)) { 1439 keepon = FALSE; 1440 result = CURLE_READ_ERROR; 1441 break; 1442 } 1443 1444 result = send_telnet_data(data, tn, buffer, readfile_read); 1445 if(result) { 1446 keepon = FALSE; 1447 break; 1448 } 1449 } 1450 break; 1451 1452 case WAIT_OBJECT_0: 1453 { 1454 events.lNetworkEvents = 0; 1455 if(WSAEnumNetworkEvents(sockfd, event_handle, &events) == SOCKET_ERROR) { 1456 err = SOCKERRNO; 1457 if(err != SOCKEINPROGRESS) { 1458 infof(data, "WSAEnumNetworkEvents failed (%d)", err); 1459 keepon = FALSE; 1460 result = CURLE_READ_ERROR; 1461 } 1462 break; 1463 } 1464 if(events.lNetworkEvents & FD_READ) { 1465 /* read data from network */ 1466 size_t nread; 1467 result = Curl_xfer_recv(data, buffer, sizeof(buffer), &nread); 1468 /* read would have 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) { 1479 keepon = FALSE; 1480 break; 1481 } 1482 1483 result = telrcv(data, tn, (unsigned char *) buffer, nread); 1484 if(result) { 1485 keepon = FALSE; 1486 break; 1487 } 1488 1489 /* Negotiate if the peer has started negotiating, 1490 otherwise do not. We do not want to speak telnet with 1491 non-telnet servers, like POP or SMTP. */ 1492 if(tn->please_negotiate && !tn->already_negotiated) { 1493 telnet_negotiate(data, tn); 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 = curlx_now(); 1507 if(curlx_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 if(pfd[1].fd < 0) { 1534 failf(data, "cannot read input"); 1535 result = CURLE_RECV_ERROR; 1536 keepon = FALSE; 1537 } 1538 } 1539 1540 while(keepon) { 1541 DEBUGF(infof(data, "telnet_do, poll %d fds", poll_cnt)); 1542 switch(Curl_poll(pfd, (unsigned int)poll_cnt, interval_ms)) { 1543 case -1: /* error, stop reading */ 1544 keepon = FALSE; 1545 continue; 1546 case 0: /* timeout */ 1547 pfd[0].revents = 0; 1548 pfd[1].revents = 0; 1549 FALLTHROUGH(); 1550 default: /* read! */ 1551 if(pfd[0].revents & POLLIN) { 1552 /* read data from network */ 1553 size_t nread; 1554 result = Curl_xfer_recv(data, buffer, sizeof(buffer), &nread); 1555 /* read would have blocked. Loop again */ 1556 if(result == CURLE_AGAIN) 1557 break; 1558 /* returned not-zero, this an error */ 1559 if(result) { 1560 keepon = FALSE; 1561 /* In test 1452, macOS sees a ECONNRESET sometimes? Is this the 1562 * telnet test server not shutting down the socket in a clean way? 1563 * Seems to be timing related, happens more on slow debug build */ 1564 if(data->state.os_errno == SOCKECONNRESET) { 1565 DEBUGF(infof(data, "telnet_do, unexpected ECONNRESET on recv")); 1566 } 1567 break; 1568 } 1569 /* returned zero but actually received 0 or less here, 1570 the server closed the connection and we bail out */ 1571 else if(!nread) { 1572 keepon = FALSE; 1573 break; 1574 } 1575 1576 total_dl += nread; 1577 result = Curl_pgrsSetDownloadCounter(data, total_dl); 1578 if(!result) 1579 result = telrcv(data, tn, (unsigned char *)buffer, nread); 1580 if(result) { 1581 keepon = FALSE; 1582 break; 1583 } 1584 1585 /* Negotiate if the peer has started negotiating, 1586 otherwise do not. We do not want to speak telnet with 1587 non-telnet servers, like POP or SMTP. */ 1588 if(tn->please_negotiate && !tn->already_negotiated) { 1589 telnet_negotiate(data, tn); 1590 tn->already_negotiated = 1; 1591 } 1592 } 1593 1594 snread = 0; 1595 if(poll_cnt == 2) { 1596 if(pfd[1].revents & POLLIN) { /* read from in file */ 1597 snread = read(pfd[1].fd, buffer, sizeof(buffer)); 1598 } 1599 } 1600 else { 1601 /* read from user-supplied method */ 1602 snread = (int)data->state.fread_func(buffer, 1, sizeof(buffer), 1603 data->state.in); 1604 if(snread == CURL_READFUNC_ABORT) { 1605 keepon = FALSE; 1606 break; 1607 } 1608 if(snread == CURL_READFUNC_PAUSE) 1609 break; 1610 } 1611 1612 if(snread > 0) { 1613 result = send_telnet_data(data, tn, buffer, snread); 1614 if(result) { 1615 keepon = FALSE; 1616 break; 1617 } 1618 total_ul += snread; 1619 Curl_pgrsSetUploadCounter(data, total_ul); 1620 } 1621 else if(snread < 0) 1622 keepon = FALSE; 1623 1624 break; 1625 } /* poll switch statement */ 1626 1627 if(data->set.timeout) { 1628 now = curlx_now(); 1629 if(curlx_timediff(now, conn->created) >= data->set.timeout) { 1630 failf(data, "Time-out"); 1631 result = CURLE_OPERATION_TIMEDOUT; 1632 keepon = FALSE; 1633 } 1634 } 1635 1636 if(Curl_pgrsUpdate(data)) { 1637 result = CURLE_ABORTED_BY_CALLBACK; 1638 break; 1639 } 1640 } 1641 #endif 1642 /* mark this as "no further transfer wanted" */ 1643 Curl_xfer_setup_nop(data); 1644 1645 return result; 1646 } 1647 #endif