Пример #1
0
/****************************************************************************
  Send all waiting data. Return TRUE on success.
****************************************************************************/
static bool conn_compression_flush(struct connection *pconn)
{
  int compression_level = get_compression_level();
  uLongf compressed_size = 12 + 1.001 * pconn->compression.queue.size;
  int error;
  Bytef compressed[compressed_size];

  error = compress2(compressed, &compressed_size,
                    pconn->compression.queue.p,
                    pconn->compression.queue.size,
                    compression_level);
  fc_assert_ret_val(error == Z_OK, FALSE);
  if (compressed_size + 2 < pconn->compression.queue.size) {
    struct data_out dout;

    log_compress("COMPRESS: compressed %lu bytes to %ld (level %d)",
                 (unsigned long) pconn->compression.queue.size,
                 compressed_size, compression_level);
    stat_size_uncompressed += pconn->compression.queue.size;
    stat_size_compressed += compressed_size;

    if (compressed_size <= JUMBO_BORDER) {
      unsigned char header[2];

      log_compress("COMPRESS: sending %ld as normal", compressed_size);

      dio_output_init(&dout, header, sizeof(header));
      dio_put_uint16(&dout, 2 + compressed_size + COMPRESSION_BORDER);
      connection_send_data(pconn, header, sizeof(header));
      connection_send_data(pconn, compressed, compressed_size);
    } else {
      unsigned char header[6];

      log_compress("COMPRESS: sending %ld as jumbo", compressed_size);
      dio_output_init(&dout, header, sizeof(header));
      dio_put_uint16(&dout, JUMBO_SIZE);
      dio_put_uint32(&dout, 6 + compressed_size);
      connection_send_data(pconn, header, sizeof(header));
      connection_send_data(pconn, compressed, compressed_size);
    }
  } else {
    log_compress("COMPRESS: would enlarging %lu bytes to %ld; "
                 "sending uncompressed",
                 (unsigned long) pconn->compression.queue.size,
                 compressed_size);
    connection_send_data(pconn, pconn->compression.queue.p,
                         pconn->compression.queue.size);
    stat_size_no_compression += pconn->compression.queue.size;
  }
  return pconn->used;
}
Пример #2
0
/****************************************************************************
  This method isn't endian safe and there will also be problems if
  sizeof(int) at serialization time is different from sizeof(int) at
  deserialization time.
****************************************************************************/
static enum attribute_serial
serialize_hash(const struct attribute_hash *hash,
               void **pdata, int *pdata_length)
{
    /*
     * Layout of version 2:
     *
     * struct {
     *   uint32 0;   always != 0 in version 1
     *   uint8 2;
     *   uint32 entries;
     *   uint32 total_size_in_bytes;
     * } preamble;
     *
     * struct {
     *   uint32 value_size;
     *   char key[], char value[];
     * } body[entries];
     */
    const size_t entries = attribute_hash_size(hash);
    int total_length, value_lengths[entries];
    void *result;
    struct data_out dout;
    int i;

    /*
     * Step 1: loop through all keys and fill value_lengths and calculate
     * the total_length.
     */
    /* preamble */
    total_length = 4 * 4;
    /* body */
    total_length += entries * (4 + 4 * 4); /* value_size + key */
    i = 0;
    attribute_hash_values_iterate(hash, pvalue) {
        struct data_in din;

        dio_input_init(&din, pvalue, 4);
        dio_get_uint32(&din, &value_lengths[i]);

        total_length += value_lengths[i];
        i++;
    }
    attribute_hash_values_iterate_end;

    /*
     * Step 2: allocate memory.
     */
    result = fc_malloc(total_length);
    dio_output_init(&dout, result, total_length);

    /*
     * Step 3: fill out the preamble.
     */
    dio_put_uint32(&dout, 0);
    dio_put_uint8(&dout, 2);
    dio_put_uint32(&dout, attribute_hash_size(hash));
    dio_put_uint32(&dout, total_length);

    /*
     * Step 4: fill out the body.
     */
    i = 0;
    attribute_hash_iterate(hash, pkey, pvalue) {
        dio_put_uint32(&dout, value_lengths[i]);

        dio_put_uint32(&dout, pkey->key);
        dio_put_uint32(&dout, pkey->id);
        dio_put_sint16(&dout, pkey->x);
        dio_put_sint16(&dout, pkey->y);

        dio_put_memory(&dout, ADD_TO_POINTER(pvalue, 4), value_lengths[i]);
        i++;
    }
Пример #3
0
/**************************************************************************
  It returns the request id of the outgoing packet (or 0 if pc->is_server).
**************************************************************************/
int send_packet_data(struct connection *pc, unsigned char *data, int len)
{
  /* default for the server */
  int result = 0;

  freelog(BASIC_PACKET_LOG_LEVEL, "sending packet type=%s(%d) len=%d",
	  get_packet_name(data[2]), data[2], len);

  if (!pc->is_server) {
    pc->client.last_request_id_used =
	get_next_request_id(pc->client.last_request_id_used);
    result = pc->client.last_request_id_used;
    freelog(BASIC_PACKET_LOG_LEVEL, "sending request %d", result);
  }

  if (pc->outgoing_packet_notify) {
    pc->outgoing_packet_notify(pc, data[2], len, result);
  }

#ifdef USE_COMPRESSION
  if(TRUE) {
    static int stat_size_alone, stat_size_uncompressed, stat_size_compressed,
	stat_size_no_compression;
    static bool compression_level_initialized = FALSE;
    static int compression_level;
    int packet_type = data[2];
    int size = len;

    if (!compression_level_initialized) {
      char *s = getenv("FREECIV_COMPRESSION_LEVEL");
      if (!s || sscanf(s, "%d", &compression_level) != 1
	  || compression_level < -1 || compression_level > 9) {
	compression_level = -1;
      }
      compression_level_initialized = TRUE;
    }

    /* TODO: PACKET_FREEZE_HINT and PACKET_THAW_HINT are meaningful
     * only internally. They should not be sent to connection at all.
     * Freezing could also be handled via separate functions, and
     * not by special packets.
     * Only problem is backward compatibility, so this cannot be
     * changed in stable branch. */
    if (packet_type == PACKET_PROCESSING_STARTED
	|| packet_type == PACKET_FREEZE_HINT) {
      if (pc->compression.frozen_level == 0) {
	byte_vector_reserve(&pc->compression.queue, 0);
      }
      pc->compression.frozen_level++;
    }

    if (pc->compression.frozen_level > 0) {
      size_t old_size = pc->compression.queue.size;

      byte_vector_reserve(&pc->compression.queue, old_size + len);
      memcpy(pc->compression.queue.p + old_size, data, len);
      freelog(COMPRESS2_LOG_LEVEL, "COMPRESS: putting %s into the queue",
	      get_packet_name(packet_type));
    } else {
      stat_size_alone += size;
      freelog(COMPRESS_LOG_LEVEL, "COMPRESS: sending %s alone (%d bytes total)",
	      get_packet_name(packet_type), stat_size_alone);
      send_connection_data(pc, data, len);
    }

    if (packet_type ==
	PACKET_PROCESSING_FINISHED || packet_type == PACKET_THAW_HINT) {
      pc->compression.frozen_level--;
      if (pc->compression.frozen_level == 0) {
	uLongf compressed_size = 12 + pc->compression.queue.size * 1.001;
	int error;
	Bytef compressed[compressed_size];

	error =
	    compress2(compressed, &compressed_size,
		      pc->compression.queue.p, pc->compression.queue.size,
		      compression_level);
	assert(error == Z_OK);
	if (compressed_size + 2 < pc->compression.queue.size) {
	    struct data_out dout;

	  freelog(COMPRESS_LOG_LEVEL,
		  "COMPRESS: compressed %lu bytes to %ld (level %d)",
		  (unsigned long)pc->compression.queue.size, compressed_size,
		  compression_level);
	  stat_size_uncompressed += pc->compression.queue.size;
	  stat_size_compressed += compressed_size;

	  if (compressed_size <= JUMBO_BORDER) {
	    unsigned char header[2];

	    freelog(COMPRESS_LOG_LEVEL, "COMPRESS: sending %ld as normal",
		    compressed_size);

	    dio_output_init(&dout, header, sizeof(header));
	    dio_put_uint16(&dout, 2 + compressed_size + COMPRESSION_BORDER);
	    send_connection_data(pc, header, sizeof(header));
	    send_connection_data(pc, compressed, compressed_size);
	  } else {
	    unsigned char header[6];

	    freelog(COMPRESS_LOG_LEVEL, "COMPRESS: sending %ld as jumbo",
		    compressed_size);
	    dio_output_init(&dout, header, sizeof(header));
	    dio_put_uint16(&dout, JUMBO_SIZE);
	    dio_put_uint32(&dout, 6 + compressed_size);
	    send_connection_data(pc, header, sizeof(header));
	    send_connection_data(pc, compressed, compressed_size);
	  }
	} else {
	  freelog(COMPRESS_LOG_LEVEL,
		  "COMPRESS: would enlarging %lu bytes to %ld; sending uncompressed",
		  (unsigned long)pc->compression.queue.size, compressed_size);
	  send_connection_data(pc, pc->compression.queue.p,
			       pc->compression.queue.size);
	  stat_size_no_compression += pc->compression.queue.size;
	}
      }
    }
    freelog(COMPRESS2_LOG_LEVEL,
	    "COMPRESS: STATS: alone=%d compression-expand=%d compression (before/after) = %d/%d",
	    stat_size_alone, stat_size_no_compression,
	    stat_size_uncompressed, stat_size_compressed);
  }
#else
  send_connection_data(pc, data, len);
#endif

#if PACKET_SIZE_STATISTICS
  {
    static struct {
      int counter;
      int size;
    } packets_stats[PACKET_LAST];
    static int packet_counter = 0;
    static int last_start_turn_seen = -1;
    static bool start_turn_seen = FALSE;

    int packet_type = data[2];
    int size = len;
    bool print = FALSE;
    bool clear = FALSE;

    if (!packet_counter) {
      int i;

      for (i = 0; i < PACKET_LAST; i++) {
	packets_stats[i].counter = 0;
	packets_stats[i].size = 0;
      }
    }

    packets_stats[packet_type].counter++;
    packets_stats[packet_type].size += size;

    packet_counter++;
    if (packet_type == PACKET_START_TURN
	&& last_start_turn_seen != game.turn) {
	start_turn_seen=TRUE;
      last_start_turn_seen = game.turn;
    }

    if ((packet_type ==
	 PACKET_PROCESSING_FINISHED || packet_type == PACKET_THAW_HINT)
	&& start_turn_seen) {
      start_turn_seen = FALSE;
      print = TRUE;
      clear = TRUE;
    }

    if(print) {
      int i, sum = 0;
      int ll = LOG_DEBUG;

#if PACKET_SIZE_STATISTICS == 2
      delta_stats_report();
#endif
      freelog(ll, "Transmitted packets:");
      freelog(ll, "%8s %8s %8s %s", "Packets", "Bytes",
	      "Byt/Pac", "Name");

      for (i = 0; i < PACKET_LAST; i++) {
	if (packets_stats[i].counter == 0) {
	  continue;
	}
	sum += packets_stats[i].size;
	freelog(ll, "%8d %8d %8d %s(%i)",
		packets_stats[i].counter, packets_stats[i].size,
		packets_stats[i].size / packets_stats[i].counter,
		get_packet_name(i),i);
      }
      freelog(LOG_TEST,
	      "turn=%d; transmitted %d bytes in %d packets;average size "
	      "per packet %d bytes", game.turn, sum, packet_counter,
	      sum / packet_counter);
      freelog(LOG_TEST, "turn=%d; transmitted %d bytes", game.turn,
	      pc->statistics.bytes_send);
    }    
    if (clear) {
      int i;

      for (i = 0; i < PACKET_LAST; i++) {
	packets_stats[i].counter = 0;
	packets_stats[i].size = 0;
      }
      packet_counter = 0;
      pc->statistics.bytes_send = 0;
      delta_stats_reset();
    }
  }
#endif

  return result;
}
Пример #4
0
/****************************************************************************
  Send all waiting data. Return TRUE on success.
****************************************************************************/
static bool conn_compression_flush(struct connection *pconn)
{
  int compression_level = get_compression_level();
  uLongf compressed_size = 12 + 1.001 * pconn->compression.queue.size;
  int error;
  Bytef compressed[compressed_size];
  bool jumbo;
  unsigned long compressed_packet_len;

  error = compress2(compressed, &compressed_size,
                    pconn->compression.queue.p,
                    pconn->compression.queue.size,
                    compression_level);
  fc_assert_ret_val(error == Z_OK, FALSE);

  /* Compression signalling currently assumes a 2-byte packet length; if that
   * changes, the protocol should probably be changed */
  fc_assert_ret_val(data_type_size(pconn->packet_header.length) == 2, FALSE);

  /* Include normal length field in decision */
  jumbo = (compressed_size+2 >= JUMBO_BORDER);

  compressed_packet_len = compressed_size + (jumbo ? 6 : 2);
  if (compressed_packet_len < pconn->compression.queue.size) {
    struct data_out dout;

    log_compress("COMPRESS: compressed %lu bytes to %ld (level %d)",
                 (unsigned long) pconn->compression.queue.size,
                 compressed_size, compression_level);
    stat_size_uncompressed += pconn->compression.queue.size;
    stat_size_compressed += compressed_size;

    if (!jumbo) {
      unsigned char header[2];
      FC_STATIC_ASSERT(COMPRESSION_BORDER > MAX_LEN_PACKET,
                       uncompressed_compressed_packet_len_overlap);

      log_compress("COMPRESS: sending %ld as normal", compressed_size);

      dio_output_init(&dout, header, sizeof(header));
      dio_put_uint16(&dout, 2 + compressed_size + COMPRESSION_BORDER);
      connection_send_data(pconn, header, sizeof(header));
      connection_send_data(pconn, compressed, compressed_size);
    } else {
      unsigned char header[6];
      FC_STATIC_ASSERT(JUMBO_SIZE >= JUMBO_BORDER+COMPRESSION_BORDER,
                       compressed_normal_jumbo_packet_len_overlap);

      log_compress("COMPRESS: sending %ld as jumbo", compressed_size);
      dio_output_init(&dout, header, sizeof(header));
      dio_put_uint16(&dout, JUMBO_SIZE);
      dio_put_uint32(&dout, 6 + compressed_size);
      connection_send_data(pconn, header, sizeof(header));
      connection_send_data(pconn, compressed, compressed_size);
    }
  } else {
    log_compress("COMPRESS: would enlarge %lu bytes to %ld; "
                 "sending uncompressed",
                 (unsigned long) pconn->compression.queue.size,
                 compressed_packet_len);
    connection_send_data(pconn, pconn->compression.queue.p,
                         pconn->compression.queue.size);
    stat_size_no_compression += pconn->compression.queue.size;
  }
  return pconn->used;
}