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