Annotation of src/usr.bin/ssh/packet.c, Revision 1.1
1.1 ! deraadt 1: /*
! 2:
! 3: packet.c
! 4:
! 5: Author: Tatu Ylonen <ylo@cs.hut.fi>
! 6:
! 7: Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
! 8: All rights reserved
! 9:
! 10: Created: Sat Mar 18 02:40:40 1995 ylo
! 11:
! 12: This file contains code implementing the packet protocol and communication
! 13: with the other side. This same code is used both on client and server side.
! 14:
! 15: */
! 16:
! 17: #include "includes.h"
! 18: RCSID("$Id: packet.c,v 1.7 1999/06/14 14:41:39 bg Exp $");
! 19:
! 20: #include "xmalloc.h"
! 21: #include "randoms.h"
! 22: #include "buffer.h"
! 23: #include "packet.h"
! 24: #include "bufaux.h"
! 25: #include "ssh.h"
! 26: #include "crc32.h"
! 27: #include "cipher.h"
! 28: #include "getput.h"
! 29:
! 30: #ifdef WITH_ZLIB
! 31: #include "compress.h"
! 32: #endif /* WITH_ZLIB */
! 33:
! 34: /* This variable contains the file descriptors used for communicating with
! 35: the other side. connection_in is used for reading; connection_out
! 36: for writing. These can be the same descriptor, in which case it is
! 37: assumed to be a socket. */
! 38: static int connection_in = -1;
! 39: static int connection_out = -1;
! 40:
! 41: /* Cipher type. This value is only used to determine whether to pad the
! 42: packets with zeroes or random data. */
! 43: static int cipher_type = SSH_CIPHER_NONE;
! 44:
! 45: /* Protocol flags for the remote side. */
! 46: static unsigned int remote_protocol_flags = 0;
! 47:
! 48: /* Encryption context for receiving data. This is only used for decryption. */
! 49: static CipherContext receive_context;
! 50: /* Encryption coontext for sending data. This is only used for encryption. */
! 51: static CipherContext send_context;
! 52:
! 53: /* Buffer for raw input data from the socket. */
! 54: static Buffer input;
! 55:
! 56: /* Buffer for raw output data going to the socket. */
! 57: static Buffer output;
! 58:
! 59: /* Buffer for the partial outgoing packet being constructed. */
! 60: static Buffer outgoing_packet;
! 61:
! 62: /* Buffer for the incoming packet currently being processed. */
! 63: static Buffer incoming_packet;
! 64:
! 65: /* Scratch buffer for packet compression/decompression. */
! 66: static Buffer compression_buffer;
! 67:
! 68: #ifdef WITH_ZLIB
! 69: /* Flag indicating whether packet compression/decompression is enabled. */
! 70: static int packet_compression = 0;
! 71: #endif /* WITH_ZLIB */
! 72:
! 73: /* Pointer to the random number generator state. */
! 74: static RandomState *random_state;
! 75:
! 76: /* Flag indicating whether this module has been initialized. */
! 77: static int initialized = 0;
! 78:
! 79: /* Set to true if the connection is interactive. */
! 80: static int interactive_mode = 0;
! 81:
! 82: /* Sets the descriptors used for communication. Disables encryption until
! 83: packet_set_encryption_key is called. */
! 84:
! 85: void packet_set_connection(int fd_in, int fd_out, RandomState *state)
! 86: {
! 87: connection_in = fd_in;
! 88: connection_out = fd_out;
! 89: random_state = state;
! 90: cipher_type = SSH_CIPHER_NONE;
! 91: cipher_set_key(&send_context, SSH_CIPHER_NONE, (unsigned char *)"", 0, 1);
! 92: cipher_set_key(&receive_context, SSH_CIPHER_NONE, (unsigned char *)"", 0, 0);
! 93: if (!initialized)
! 94: {
! 95: initialized = 1;
! 96: buffer_init(&input);
! 97: buffer_init(&output);
! 98: buffer_init(&outgoing_packet);
! 99: buffer_init(&incoming_packet);
! 100: }
! 101:
! 102: /* Kludge: arrange the close function to be called from fatal(). */
! 103: fatal_add_cleanup((void (*)(void *))packet_close, NULL);
! 104: }
! 105:
! 106: /* Sets the connection into non-blocking mode. */
! 107:
! 108: void packet_set_nonblocking()
! 109: {
! 110: /* Set the socket into non-blocking mode. */
! 111: #if defined(O_NONBLOCK) && !defined(O_NONBLOCK_BROKEN)
! 112: if (fcntl(connection_in, F_SETFL, O_NONBLOCK) < 0)
! 113: error("fcntl O_NONBLOCK: %.100s", strerror(errno));
! 114: #else /* O_NONBLOCK && !O_NONBLOCK_BROKEN */
! 115: if (fcntl(connection_in, F_SETFL, O_NDELAY) < 0)
! 116: error("fcntl O_NDELAY: %.100s", strerror(errno));
! 117: #endif /* O_NONBLOCK && !O_NONBLOCK_BROKEN */
! 118:
! 119: if (connection_out != connection_in)
! 120: {
! 121: #if defined(O_NONBLOCK) && !defined(O_NONBLOCK_BROKEN)
! 122: if (fcntl(connection_out, F_SETFL, O_NONBLOCK) < 0)
! 123: error("fcntl O_NONBLOCK: %.100s", strerror(errno));
! 124: #else /* O_NONBLOCK && !O_NONBLOCK_BROKEN */
! 125: if (fcntl(connection_out, F_SETFL, O_NDELAY) < 0)
! 126: error("fcntl O_NDELAY: %.100s", strerror(errno));
! 127: #endif /* O_NONBLOCK && !O_NONBLOCK_BROKEN */
! 128: }
! 129: }
! 130:
! 131: /* Returns the socket used for reading. */
! 132:
! 133: int packet_get_connection_in()
! 134: {
! 135: return connection_in;
! 136: }
! 137:
! 138: /* Returns the descriptor used for writing. */
! 139:
! 140: int packet_get_connection_out()
! 141: {
! 142: return connection_out;
! 143: }
! 144:
! 145: /* Closes the connection and clears and frees internal data structures. */
! 146:
! 147: void packet_close()
! 148: {
! 149: if (!initialized)
! 150: return;
! 151: initialized = 0;
! 152: if (connection_in == connection_out)
! 153: {
! 154: shutdown(connection_out, 2);
! 155: close(connection_out);
! 156: }
! 157: else
! 158: {
! 159: close(connection_in);
! 160: close(connection_out);
! 161: }
! 162: buffer_free(&input);
! 163: buffer_free(&output);
! 164: buffer_free(&outgoing_packet);
! 165: buffer_free(&incoming_packet);
! 166: #ifdef WITH_ZLIB
! 167: if (packet_compression)
! 168: {
! 169: buffer_free(&compression_buffer);
! 170: buffer_compress_uninit();
! 171: }
! 172: #endif /* WITH_ZLIB */
! 173: }
! 174:
! 175: /* Sets remote side protocol flags. */
! 176:
! 177: void packet_set_protocol_flags(unsigned int protocol_flags)
! 178: {
! 179: remote_protocol_flags = protocol_flags;
! 180: channel_set_options((protocol_flags & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) != 0);
! 181: }
! 182:
! 183: /* Returns the remote protocol flags set earlier by the above function. */
! 184:
! 185: unsigned int packet_get_protocol_flags()
! 186: {
! 187: return remote_protocol_flags;
! 188: }
! 189:
! 190: #ifdef WITH_ZLIB
! 191: /* Starts packet compression from the next packet on in both directions.
! 192: Level is compression level 1 (fastest) - 9 (slow, best) as in gzip. */
! 193:
! 194: void packet_start_compression(int level)
! 195: {
! 196: if (packet_compression)
! 197: fatal("Compression already enabled.");
! 198: packet_compression = 1;
! 199: buffer_init(&compression_buffer);
! 200: buffer_compress_init(level);
! 201: }
! 202: #endif /* WITH_ZLIB */
! 203:
! 204: /* Encrypts the given number of bytes, copying from src to dest.
! 205: bytes is known to be a multiple of 8. */
! 206:
! 207: void packet_encrypt(CipherContext *cc, void *dest, void *src,
! 208: unsigned int bytes)
! 209: {
! 210: assert((bytes % 8) == 0);
! 211: cipher_encrypt(cc, dest, src, bytes);
! 212: }
! 213:
! 214: /* Decrypts the given number of bytes, copying from src to dest.
! 215: bytes is known to be a multiple of 8. */
! 216:
! 217: void packet_decrypt(CipherContext *cc, void *dest, void *src,
! 218: unsigned int bytes)
! 219: {
! 220: assert((bytes % 8) == 0);
! 221: cipher_decrypt(cc, dest, src, bytes);
! 222: }
! 223:
! 224: /* Causes any further packets to be encrypted using the given key. The same
! 225: key is used for both sending and reception. However, both directions
! 226: are encrypted independently of each other. */
! 227:
! 228: void packet_set_encryption_key(const unsigned char *key, unsigned int keylen,
! 229: int cipher, int is_client)
! 230: {
! 231: cipher_type = cipher;
! 232: if (cipher == SSH_CIPHER_RC4)
! 233: {
! 234: if (is_client)
! 235: { /* In client: use first half for receiving, second for sending. */
! 236: cipher_set_key(&receive_context, cipher, key, keylen / 2, 0);
! 237: cipher_set_key(&send_context, cipher, key + keylen / 2,
! 238: keylen / 2, 1);
! 239: }
! 240: else
! 241: { /* In server: use first half for sending, second for receiving. */
! 242: cipher_set_key(&receive_context, cipher, key + keylen / 2,
! 243: keylen / 2, 0);
! 244: cipher_set_key(&send_context, cipher, key, keylen / 2, 1);
! 245: }
! 246: }
! 247: else
! 248: {
! 249: /* All other ciphers use the same key in both directions for now. */
! 250: cipher_set_key(&receive_context, cipher, key, keylen, 0);
! 251: cipher_set_key(&send_context, cipher, key, keylen, 1);
! 252: }
! 253: }
! 254:
! 255: /* Starts constructing a packet to send. */
! 256:
! 257: void packet_start(int type)
! 258: {
! 259: char buf[9];
! 260:
! 261: buffer_clear(&outgoing_packet);
! 262: memset(buf, 0, 8);
! 263: buf[8] = type;
! 264: buffer_append(&outgoing_packet, buf, 9);
! 265: }
! 266:
! 267: /* Appends a character to the packet data. */
! 268:
! 269: void packet_put_char(int value)
! 270: {
! 271: char ch = value;
! 272: buffer_append(&outgoing_packet, &ch, 1);
! 273: }
! 274:
! 275: /* Appends an integer to the packet data. */
! 276:
! 277: void packet_put_int(unsigned int value)
! 278: {
! 279: buffer_put_int(&outgoing_packet, value);
! 280: }
! 281:
! 282: /* Appends a string to packet data. */
! 283:
! 284: void packet_put_string(const char *buf, unsigned int len)
! 285: {
! 286: buffer_put_string(&outgoing_packet, buf, len);
! 287: }
! 288:
! 289: /* Appends an arbitrary precision integer to packet data. */
! 290:
! 291: void packet_put_mp_int(MP_INT *value)
! 292: {
! 293: buffer_put_mp_int(&outgoing_packet, value);
! 294: }
! 295:
! 296: /* Finalizes and sends the packet. If the encryption key has been set,
! 297: encrypts the packet before sending. */
! 298:
! 299: void packet_send()
! 300: {
! 301: char buf[8], *cp;
! 302: int i, padding, len;
! 303: unsigned long checksum;
! 304:
! 305: #ifdef WITH_ZLIB
! 306: /* If using packet compression, compress the payload of the outgoing
! 307: packet. */
! 308: if (packet_compression)
! 309: {
! 310: buffer_clear(&compression_buffer);
! 311: buffer_consume(&outgoing_packet, 8); /* Skip padding. */
! 312: buffer_append(&compression_buffer, "\0\0\0\0\0\0\0\0", 8); /* padding */
! 313: buffer_compress(&outgoing_packet, &compression_buffer);
! 314: buffer_clear(&outgoing_packet);
! 315: buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer),
! 316: buffer_len(&compression_buffer));
! 317: }
! 318: #endif /* WITH_ZLIB */
! 319:
! 320: /* Compute packet length without padding (add checksum, remove padding). */
! 321: len = buffer_len(&outgoing_packet) + 4 - 8;
! 322:
! 323: /* Insert padding. */
! 324: padding = 8 - len % 8;
! 325: if (cipher_type != SSH_CIPHER_NONE)
! 326: {
! 327: cp = buffer_ptr(&outgoing_packet);
! 328: for (i = 0; i < padding; i++)
! 329: cp[7 - i] = random_get_byte(random_state);
! 330: }
! 331: buffer_consume(&outgoing_packet, 8 - padding);
! 332:
! 333: /* Add check bytes. */
! 334: checksum = crc32((unsigned char *)buffer_ptr(&outgoing_packet),
! 335: buffer_len(&outgoing_packet));
! 336: PUT_32BIT(buf, checksum);
! 337: buffer_append(&outgoing_packet, buf, 4);
! 338:
! 339: #ifdef PACKET_DEBUG
! 340: fprintf(stderr, "packet_send plain: ");
! 341: buffer_dump(&outgoing_packet);
! 342: #endif
! 343:
! 344: /* Append to output. */
! 345: PUT_32BIT(buf, len);
! 346: buffer_append(&output, buf, 4);
! 347: buffer_append_space(&output, &cp, buffer_len(&outgoing_packet));
! 348: packet_encrypt(&send_context, cp, buffer_ptr(&outgoing_packet),
! 349: buffer_len(&outgoing_packet));
! 350:
! 351: #ifdef PACKET_DEBUG
! 352: fprintf(stderr, "encrypted: "); buffer_dump(&output);
! 353: #endif
! 354:
! 355: buffer_clear(&outgoing_packet);
! 356:
! 357: /* Note that the packet is now only buffered in output. It won\'t be
! 358: actually sent until packet_write_wait or packet_write_poll is called. */
! 359: }
! 360:
! 361: /* Waits until a packet has been received, and returns its type. Note that
! 362: no other data is processed until this returns, so this function should
! 363: not be used during the interactive session. */
! 364:
! 365: int packet_read(int *payload_len_ptr)
! 366: {
! 367: int type, len;
! 368: fd_set set;
! 369: char buf[8192];
! 370:
! 371: /* Since we are blocking, ensure that all written packets have been sent. */
! 372: packet_write_wait();
! 373:
! 374: /* Stay in the loop until we have received a complete packet. */
! 375: for (;;)
! 376: {
! 377: /* Try to read a packet from the buffer. */
! 378: type = packet_read_poll(payload_len_ptr);
! 379: if (type == SSH_SMSG_SUCCESS
! 380: || type == SSH_SMSG_FAILURE
! 381: || type == SSH_CMSG_EOF
! 382: || type == SSH_CMSG_EXIT_CONFIRMATION)
! 383: packet_integrity_check(*payload_len_ptr, 0, type);
! 384: /* If we got a packet, return it. */
! 385: if (type != SSH_MSG_NONE)
! 386: return type;
! 387: /* Otherwise, wait for some data to arrive, add it to the buffer,
! 388: and try again. */
! 389: FD_ZERO(&set);
! 390: FD_SET(connection_in, &set);
! 391: /* Wait for some data to arrive. */
! 392: select(connection_in + 1, &set, NULL, NULL, NULL);
! 393: /* Read data from the socket. */
! 394: len = read(connection_in, buf, sizeof(buf));
! 395: if (len == 0)
! 396: fatal("Connection closed by remote host.");
! 397: if (len < 0)
! 398: fatal("Read from socket failed: %.100s", strerror(errno));
! 399: /* Append it to the buffer. */
! 400: packet_process_incoming(buf, len);
! 401: }
! 402: /*NOTREACHED*/
! 403: }
! 404:
! 405: /* Waits until a packet has been received, verifies that its type matches
! 406: that given, and gives a fatal error and exits if there is a mismatch. */
! 407:
! 408: void packet_read_expect(int *payload_len_ptr, int expected_type)
! 409: {
! 410: int type;
! 411:
! 412: type = packet_read(payload_len_ptr);
! 413: if (type != expected_type)
! 414: packet_disconnect("Protocol error: expected packet type %d, got %d",
! 415: expected_type, type);
! 416: }
! 417:
! 418: /* Checks if a full packet is available in the data received so far via
! 419: packet_process_incoming. If so, reads the packet; otherwise returns
! 420: SSH_MSG_NONE. This does not wait for data from the connection.
! 421:
! 422: SSH_MSG_DISCONNECT is handled specially here. Also,
! 423: SSH_MSG_IGNORE messages are skipped by this function and are never returned
! 424: to higher levels.
! 425:
! 426: The returned payload_len does include space consumed by:
! 427: Packet length
! 428: Padding
! 429: Packet type
! 430: Check bytes
! 431:
! 432:
! 433: */
! 434:
! 435: int packet_read_poll(int *payload_len_ptr)
! 436: {
! 437: unsigned int len, padded_len;
! 438: unsigned char *ucp;
! 439: char buf[8], *cp;
! 440: unsigned long checksum, stored_checksum;
! 441:
! 442: restart:
! 443:
! 444: /* Check if input size is less than minimum packet size. */
! 445: if (buffer_len(&input) < 4 + 8)
! 446: return SSH_MSG_NONE;
! 447: /* Get length of incoming packet. */
! 448: ucp = (unsigned char *)buffer_ptr(&input);
! 449: len = GET_32BIT(ucp);
! 450: if (len < 1 + 2 + 2 || len > 256*1024)
! 451: packet_disconnect("Bad packet length %d.", len);
! 452: padded_len = (len + 8) & ~7;
! 453:
! 454: /* Check if the packet has been entirely received. */
! 455: if (buffer_len(&input) < 4 + padded_len)
! 456: return SSH_MSG_NONE;
! 457:
! 458: /* The entire packet is in buffer. */
! 459:
! 460: /* Consume packet length. */
! 461: buffer_consume(&input, 4);
! 462:
! 463: /* Copy data to incoming_packet. */
! 464: buffer_clear(&incoming_packet);
! 465: buffer_append_space(&incoming_packet, &cp, padded_len);
! 466: packet_decrypt(&receive_context, cp, buffer_ptr(&input), padded_len);
! 467: buffer_consume(&input, padded_len);
! 468:
! 469: #ifdef PACKET_DEBUG
! 470: fprintf(stderr, "read_poll plain: "); buffer_dump(&incoming_packet);
! 471: #endif
! 472:
! 473: /* Compute packet checksum. */
! 474: checksum = crc32((unsigned char *)buffer_ptr(&incoming_packet),
! 475: buffer_len(&incoming_packet) - 4);
! 476:
! 477: /* Skip padding. */
! 478: buffer_consume(&incoming_packet, 8 - len % 8);
! 479:
! 480: /* Test check bytes. */
! 481: assert(len == buffer_len(&incoming_packet));
! 482: ucp = (unsigned char *)buffer_ptr(&incoming_packet) + len - 4;
! 483: stored_checksum = GET_32BIT(ucp);
! 484: if (checksum != stored_checksum)
! 485: packet_disconnect("Corrupted check bytes on input.");
! 486: buffer_consume_end(&incoming_packet, 4);
! 487:
! 488: #ifdef WITH_ZLIB
! 489: /* If using packet compression, decompress the packet. */
! 490: if (packet_compression)
! 491: {
! 492: buffer_clear(&compression_buffer);
! 493: buffer_uncompress(&incoming_packet, &compression_buffer);
! 494: buffer_clear(&incoming_packet);
! 495: buffer_append(&incoming_packet, buffer_ptr(&compression_buffer),
! 496: buffer_len(&compression_buffer));
! 497: }
! 498: #endif /* WITH_ZLIB */
! 499:
! 500: /* Get packet type. */
! 501: buffer_get(&incoming_packet, &buf[0], 1);
! 502:
! 503: /* Return length of payload (without type field). */
! 504: *payload_len_ptr = buffer_len(&incoming_packet);
! 505:
! 506: /* Handle disconnect message. */
! 507: if ((unsigned char)buf[0] == SSH_MSG_DISCONNECT)
! 508: fatal("%.900s", packet_get_string(NULL));
! 509:
! 510: /* Ignore ignore messages. */
! 511: if ((unsigned char)buf[0] == SSH_MSG_IGNORE)
! 512: goto restart;
! 513:
! 514: /* Send debug messages as debugging output. */
! 515: if ((unsigned char)buf[0] == SSH_MSG_DEBUG)
! 516: {
! 517: debug("Remote: %.900s", packet_get_string(NULL));
! 518: goto restart;
! 519: }
! 520:
! 521: /* Return type. */
! 522: return (unsigned char)buf[0];
! 523: }
! 524:
! 525: /* Buffers the given amount of input characters. This is intended to be
! 526: used together with packet_read_poll. */
! 527:
! 528: void packet_process_incoming(const char *buf, unsigned int len)
! 529: {
! 530: buffer_append(&input, buf, len);
! 531: }
! 532:
! 533: /* Returns a character from the packet. */
! 534:
! 535: unsigned int packet_get_char()
! 536: {
! 537: char ch;
! 538: buffer_get(&incoming_packet, &ch, 1);
! 539: return (unsigned char)ch;
! 540: }
! 541:
! 542: /* Returns an integer from the packet data. */
! 543:
! 544: unsigned int packet_get_int()
! 545: {
! 546: return buffer_get_int(&incoming_packet);
! 547: }
! 548:
! 549: /* Returns an arbitrary precision integer from the packet data. The integer
! 550: must have been initialized before this call. */
! 551:
! 552: void packet_get_mp_int(MP_INT *value, int *length_ptr)
! 553: {
! 554: *length_ptr = buffer_get_mp_int(&incoming_packet, value);
! 555: }
! 556:
! 557: /* Returns a string from the packet data. The string is allocated using
! 558: xmalloc; it is the responsibility of the calling program to free it when
! 559: no longer needed. The length_ptr argument may be NULL, or point to an
! 560: integer into which the length of the string is stored. */
! 561:
! 562: char *packet_get_string(unsigned int *length_ptr)
! 563: {
! 564: return buffer_get_string(&incoming_packet, length_ptr);
! 565: }
! 566:
! 567: /* Sends a diagnostic message from the server to the client. This message
! 568: can be sent at any time (but not while constructing another message).
! 569: The message is printed immediately, but only if the client is being
! 570: executed in verbose mode. These messages are primarily intended to
! 571: ease debugging authentication problems. The length of the formatted
! 572: message must not exceed 1024 bytes. This will automatically call
! 573: packet_write_wait. */
! 574:
! 575: void packet_send_debug(const char *fmt, ...)
! 576: {
! 577: char buf[1024];
! 578: va_list args;
! 579:
! 580: va_start(args, fmt);
! 581: vsnprintf(buf, sizeof(buf), fmt, args);
! 582: va_end(args);
! 583:
! 584: packet_start(SSH_MSG_DEBUG);
! 585: packet_put_string(buf, strlen(buf));
! 586: packet_send();
! 587: packet_write_wait();
! 588: }
! 589:
! 590: /* Logs the error plus constructs and sends a disconnect
! 591: packet, closes the connection, and exits. This function never returns.
! 592: The error message should not contain a newline. The length of the
! 593: formatted message must not exceed 1024 bytes. */
! 594:
! 595: void packet_disconnect(const char *fmt, ...)
! 596: {
! 597: char buf[1024];
! 598: va_list args;
! 599: static int disconnecting = 0;
! 600: if (disconnecting) /* Guard against recursive invocations. */
! 601: fatal("packet_disconnect called recursively.");
! 602: disconnecting = 1;
! 603:
! 604: /* Format the message. Note that the caller must make sure the message
! 605: is of limited size. */
! 606: va_start(args, fmt);
! 607: vsnprintf(buf, sizeof(buf), fmt, args);
! 608: va_end(args);
! 609:
! 610: /* Send the disconnect message to the other side, and wait for it to get
! 611: sent. */
! 612: packet_start(SSH_MSG_DISCONNECT);
! 613: packet_put_string(buf, strlen(buf));
! 614: packet_send();
! 615: packet_write_wait();
! 616:
! 617: /* Stop listening for connections. */
! 618: channel_stop_listening();
! 619:
! 620: /* Close the connection. */
! 621: packet_close();
! 622:
! 623: /* Display the error locally and exit. */
! 624: fatal("Local: %.100s", buf);
! 625: }
! 626:
! 627: /* Checks if there is any buffered output, and tries to write some of the
! 628: output. */
! 629:
! 630: void packet_write_poll()
! 631: {
! 632: int len = buffer_len(&output);
! 633: if (len > 0)
! 634: {
! 635: len = write(connection_out, buffer_ptr(&output), len);
! 636: if (len <= 0)
! 637: if (errno == EAGAIN)
! 638: return;
! 639: else
! 640: fatal("Write failed: %.100s", strerror(errno));
! 641: buffer_consume(&output, len);
! 642: }
! 643: }
! 644:
! 645: /* Calls packet_write_poll repeatedly until all pending output data has
! 646: been written. */
! 647:
! 648: void packet_write_wait()
! 649: {
! 650: packet_write_poll();
! 651: while (packet_have_data_to_write())
! 652: {
! 653: fd_set set;
! 654: FD_ZERO(&set);
! 655: FD_SET(connection_out, &set);
! 656: select(connection_out + 1, NULL, &set, NULL, NULL);
! 657: packet_write_poll();
! 658: }
! 659: }
! 660:
! 661: /* Returns true if there is buffered data to write to the connection. */
! 662:
! 663: int packet_have_data_to_write()
! 664: {
! 665: return buffer_len(&output) != 0;
! 666: }
! 667:
! 668: /* Returns true if there is not too much data to write to the connection. */
! 669:
! 670: int packet_not_very_much_data_to_write()
! 671: {
! 672: if (interactive_mode)
! 673: return buffer_len(&output) < 16384;
! 674: else
! 675: return buffer_len(&output) < 128*1024;
! 676: }
! 677:
! 678: /* Informs that the current session is interactive. Sets IP flags for that. */
! 679:
! 680: void packet_set_interactive(int interactive, int keepalives)
! 681: {
! 682: int on = 1;
! 683:
! 684: /* Record that we are in interactive mode. */
! 685: interactive_mode = interactive;
! 686:
! 687: /* Only set socket options if using a socket (as indicated by the descriptors
! 688: being the same). */
! 689: if (connection_in != connection_out)
! 690: return;
! 691:
! 692: if (keepalives)
! 693: {
! 694: /* Set keepalives if requested. */
! 695: if (setsockopt(connection_in, SOL_SOCKET, SO_KEEPALIVE, (void *)&on,
! 696: sizeof(on)) < 0)
! 697: error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
! 698: }
! 699:
! 700: if (interactive)
! 701: {
! 702: /* Set IP options for an interactive connection. Use IPTOS_LOWDELAY
! 703: and TCP_NODELAY. */
! 704: #ifdef IPTOS_LOWDELAY
! 705: int lowdelay = IPTOS_LOWDELAY;
! 706: if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *)&lowdelay,
! 707: sizeof(lowdelay)) < 0)
! 708: error("setsockopt IPTOS_LOWDELAY: %.100s", strerror(errno));
! 709: #endif /* IPTOS_LOWDELAY */
! 710: if (setsockopt(connection_in, IPPROTO_TCP, TCP_NODELAY, (void *)&on,
! 711: sizeof(on)) < 0)
! 712: error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
! 713: }
! 714: else
! 715: {
! 716: /* Set IP options for a non-interactive connection. Use
! 717: IPTOS_THROUGHPUT. */
! 718: #ifdef IPTOS_THROUGHPUT
! 719: int throughput = IPTOS_THROUGHPUT;
! 720: if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *)&throughput,
! 721: sizeof(throughput)) < 0)
! 722: error("setsockopt IPTOS_THROUGHPUT: %.100s", strerror(errno));
! 723: #endif /* IPTOS_THROUGHPUT */
! 724: }
! 725: }
! 726:
! 727: /* Returns true if the current connection is interactive. */
! 728:
! 729: int packet_is_interactive()
! 730: {
! 731: return interactive_mode;
! 732: }