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