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