25#ifdef HAVE_ARPA_INET_H
28#ifdef HAVE_NETINET_IN_H
29#include <netinet/in.h>
53#define JUMBO_SIZE 0xffff
58#define COMPRESSION_BORDER (16*1024+1)
63#define JUMBO_BORDER (64*1024-COMPRESSION_BORDER-1)
65#define log_compress log_debug
66#define log_compress2 log_debug
68#define MAX_DECOMPRESSION 400
76#define PACKET_SIZE_STATISTICS 0
80#define SPECHASH_TAG packet_handler
81#define SPECHASH_ASTR_KEY_TYPE
82#define SPECHASH_IDATA_TYPE struct packet_handlers *
83#define SPECHASH_IDATA_FREE (packet_handler_hash_data_free_fn_t) free
99 static int level = -2;
102 const char *s = getenv(
"FREECIV_COMPRESSION_LEVEL");
119 Bytef compressed[compressed_size];
121 unsigned long compressed_packet_len;
123#ifndef FREECIV_NDEBUG
126 compress2(compressed, &compressed_size,
140 compressed_packet_len = compressed_size + (jumbo ? 6 : 2);
141 if (compressed_packet_len < pconn->compression.queue.size) {
144 log_compress(
"COMPRESS: compressed %lu bytes to %ld (level %d)",
146 compressed_size, compression_level);
151 unsigned char header[2];
154 uncompressed_compressed_packet_len_overlap);
156 log_compress(
"COMPRESS: sending %ld as normal", compressed_size);
163 unsigned char header[6];
166 compressed_normal_jumbo_packet_len_overlap);
168 log_compress(
"COMPRESS: sending %ld as jumbo", compressed_size);
176 log_compress(
"COMPRESS: would enlarge %lu bytes to %ld; "
177 "sending uncompressed",
179 compressed_packet_len);
196#ifdef USE_COMPRESSION
200 "Too many calls to conn_compression_thaw on %s!",
219 log_packet(
"sending packet type=%s(%d) len=%d to %s",
234#ifdef USE_COMPRESSION
244#define MAX_LEN_COMPRESS_QUEUE (MAX_LEN_BUFFER/2)
246 compress_queue_maxlen_too_big);
252 log_compress2(
"COMPRESS: huge queue, forcing to flush (%lu/%lu)",
269 log_compress(
"COMPRESS: sending %s alone (%d bytes total)",
274 log_compress2(
"COMPRESS: STATS: alone=%d compression-expand=%d "
275 "compression (before/after) = %d/%d",
283#if PACKET_SIZE_STATISTICS
289 static int packet_counter = 0;
290 static int last_start_turn_seen = -1;
291 static bool start_turn_seen =
FALSE;
297 if (!packet_counter) {
301 packets_stats[i].counter = 0;
302 packets_stats[i].size = 0;
311 && last_start_turn_seen !=
game.turn) {
312 start_turn_seen =
TRUE;
313 last_start_turn_seen =
game.turn;
318 && start_turn_seen) {
319 start_turn_seen =
FALSE;
326#define log_ll log_debug
328#if PACKET_SIZE_STATISTICS == 2
331 log_ll(
"Transmitted packets:");
332 log_ll(
"%8s %8s %8s %s",
"Packets",
"Bytes",
"Byt/Pac",
"Name");
335 if (packets_stats[i].counter == 0) {
338 sum += packets_stats[i].size;
339 log_ll(
"%8d %8d %8d %s(%i)",
340 packets_stats[i].counter, packets_stats[i].
size,
341 packets_stats[i].
size / packets_stats[i].counter,
344 log_test(
"turn=%d; transmitted %d bytes in %d packets;average size "
345 "per packet %d bytes",
game.turn, sum, packet_counter,
346 sum / packet_counter);
354 packets_stats[i].counter = 0;
355 packets_stats[i].size = 0;
377 int whole_packet_len;
383#ifdef USE_COMPRESSION
384 bool compressed_packet =
FALSE;
388 void *(*receive_handler)(
struct connection *);
403 whole_packet_len = len_read;
405#ifdef USE_COMPRESSION
410 compressed_packet =
TRUE;
418 whole_packet_len = 6;
421 compressed_packet =
TRUE;
424 log_compress(
"COMPRESS: got a normal packet of size %d",
429 if ((
unsigned)whole_packet_len > pc->
buffer->
ndata) {
433#ifdef USE_COMPRESSION
434 if (whole_packet_len < header_size) {
435 log_verbose(
"The packet size is reported to be less than header alone. "
436 "The connection will be closed now.");
442 if (compressed_packet) {
443 uLong compressed_size = whole_packet_len - header_size;
444 int decompress_factor = 80;
445 unsigned long int decompressed_size = decompress_factor * compressed_size;
446 int error = Z_BUF_ERROR;
448 void *decompressed =
fc_malloc(decompressed_size);
452 uncompress(decompressed, &decompressed_size,
456 if (error == Z_BUF_ERROR) {
457 decompress_factor += 50;
458 decompressed_size = decompress_factor * compressed_size;
459 decompressed =
fc_realloc(decompressed, decompressed_size);
464 log_verbose(
"Uncompressing of the packet stream failed. "
465 "The connection will be closed now.");
471 }
while (error != Z_OK);
473 buffer->
ndata -= whole_packet_len;
478 memmove(buffer->
data, buffer->
data + whole_packet_len, buffer->
ndata);
480 if (buffer->
ndata + decompressed_size > buffer->
nsize) {
481 buffer->
nsize += decompressed_size;
489 memmove(buffer->
data + decompressed_size, buffer->
data, buffer->
ndata);
494 memcpy(buffer->
data, decompressed, decompressed_size);
498 buffer->
ndata += decompressed_size;
501 compressed_size, decompressed_size);
513 log_verbose(
"The packet stream is corrupt. The connection "
514 "will be closed now.");
520 utype.type = utype.itype;
524 log_verbose(
"Received unsupported packet type %d (%s). The connection "
525 "will be closed now.",
531 log_packet(
"got packet type=(%s)%d len=%d from %s",
532 packet_name(utype.type), utype.itype, whole_packet_len,
541#if PACKET_SIZE_STATISTICS
547 static int packet_counter = 0;
550 int size = whole_packet_len;
552 if (!packet_counter) {
556 packets_stats[i].counter = 0;
557 packets_stats[i].size = 0;
565 if (packet_counter % 100 == 0) {
570 if (packets_stats[i].counter == 0) {
573 sum += packets_stats[i].size;
574 log_test(
" [%-25.25s %3d]: %6d packets; %8d bytes total; "
575 "%5d bytes/packet average",
577 packets_stats[i].
size,
578 packets_stats[i].
size / packets_stats[i].counter);
580 log_test(
"received %d bytes in %d packets;average size "
581 "per packet %d bytes",
582 sum, packet_counter, sum / packet_counter);
586 data = receive_handler(pc);
607 log_debug(
"remove_packet_from_buffer: remove %d; remaining %d",
676 log_packet(
"received long packet (type %d, len %d, rem %lu) from %s",
695 log_packet(
"received attribute chunk %u/%u %u",
696 (
unsigned int) chunk->
offset,
715 log_error(
"Received wrong attribute chunk");
750 int current_chunk, chunks, bytes_left;
765 for (current_chunk = 0; current_chunk < chunks; current_chunk++) {
805 log_packet(
"sending attribute chunk %d/%d %d",
829 memset(&default_handlers, 0,
sizeof(default_handlers));
834 return &default_handlers;
847 int functional_tokens_num = 0;
850 fc_assert(strlen(capability) <
sizeof(functional_capability));
854 for (i = 0; i < tokens_num; i++) {
858 if (token[0] ==
'+') {
863 functional_tokens[functional_tokens_num++] = token;
866 qsort(functional_tokens, functional_tokens_num,
868 for (i = 0; i < functional_tokens_num; i++) {
869 if (functional_capability[0] !=
'\0') {
872 sz_strlcat(functional_capability, functional_tokens[i]);
882 if (!packet_handler_hash_lookup(
packet_handlers, functional_capability,
884 phandlers =
fc_malloc(
sizeof(*phandlers));
bool has_capability(const char *cap, const char *capstr)
int get_next_request_id(int old_request_id)
void connection_do_buffer(struct connection *pc)
void connection_close(struct connection *pconn, const char *reason)
const char * conn_description(const struct connection *pconn)
bool connection_send_data(struct connection *pconn, const unsigned char *data, int len)
bool conn_compression_frozen(const struct connection *pconn)
void connection_do_unbuffer(struct connection *pc)
void dio_output_init(struct raw_data_out *dout, void *destination, size_t dest_size)
void dio_put_uint16_raw(struct raw_data_out *dout, int value)
size_t dio_input_remaining(struct data_in *din)
bool dio_get_uint32_raw(struct data_in *din, int *dest)
void dio_input_rewind(struct data_in *din)
void dio_put_uint32_raw(struct raw_data_out *dout, int value)
bool dio_get_uint16_raw(struct data_in *din, int *dest)
bool dio_get_type_raw(struct data_in *din, enum data_type type, int *dest)
size_t data_type_size(enum data_type type)
void dio_input_init(struct data_in *din, const void *src, size_t src_size)
void free_tokens(char **tokens, size_t ntokens)
int get_tokens(const char *str, char **tokens, size_t num_tokens, const char *delimiterset)
static bool is_server(void)
#define fc_assert_ret(condition)
#define log_verbose(message,...)
#define fc_assert(condition)
#define fc_assert_action_msg(condition, action, message,...)
#define fc_assert_ret_val(condition, val)
#define log_debug(message,...)
#define log_error(message,...)
#define FC_STATIC_ASSERT(cond, tag)
#define fc_realloc(ptr, sz)
void post_receive_packet_server_join_reply(struct connection *pconn, const struct packet_server_join_reply *packet)
static void packet_handlers_free(void)
#define COMPRESSION_BORDER
void * get_packet_from_connection_raw(struct connection *pc, enum packet_type *ptype)
#define MAX_DECOMPRESSION
bool packet_check(struct data_in *din, struct connection *pc)
void packet_header_init(struct packet_header *packet_header)
bool conn_compression_thaw(struct connection *pconn)
const struct packet_handlers * packet_handlers_initial(void)
const char *const packet_functional_capability
void packets_deinit(void)
void pre_send_packet_player_attribute_chunk(struct connection *pc, struct packet_player_attribute_chunk *packet)
static void packet_header_set(struct packet_header *packet_header)
static int stat_size_compressed
static int get_compression_level(void)
void remove_packet_from_buffer(struct socket_packet_buffer *buffer)
void post_send_packet_server_join_reply(struct connection *pconn, const struct packet_server_join_reply *packet)
static int stat_size_uncompressed
int send_packet_data(struct connection *pc, unsigned char *data, int len, enum packet_type packet_type)
#define MAX_LEN_COMPRESS_QUEUE
static int stat_size_alone
void generic_handle_player_attribute_chunk(struct player *pplayer, const struct packet_player_attribute_chunk *chunk)
static int stat_size_no_compression
void send_attribute_block(const struct player *pplayer, struct connection *pconn)
const struct packet_handlers * packet_handlers_get(const char *capability)
static bool conn_compression_flush(struct connection *pconn)
#define ATTRIBUTE_CHUNK_SIZE
#define get_packet_from_connection(pc, ptype)
void packet_handlers_fill_capability(struct packet_handlers *phandlers, const char *capability)
const char * packet_name(enum packet_type type)
void packet_handlers_fill_initial(struct packet_handlers *phandlers)
void delta_stats_reset(void)
void delta_stats_report(void)
int send_packet_player_attribute_chunk(struct connection *pc, const struct packet_player_attribute_chunk *packet)
@ PACKET_PROCESSING_FINISHED
#define MAX_ATTRIBUTE_BLOCK
struct setting_list * level[OLEVELS_NUM]
int compare_strings_ptrs(const void *first, const void *second)
bool str_to_int(const char *str, int *pint)
#define ADD_TO_POINTER(p, n)
struct connection::@61 statistics
struct connection::@57::@62 client
const struct packet_handlers * handlers
struct connection::@59 phs
struct packet_header packet_header
char username[MAX_LEN_NAME]
struct connection::@60 compression
void(* incoming_packet_notify)(struct connection *pc, int packet_type, int size)
void(* outgoing_packet_notify)(struct connection *pc, int packet_type, int size, int request_id)
struct socket_packet_buffer * buffer
void *(* receive[PACKET_LAST])(struct connection *pconn)
unsigned char data[ATTRIBUTE_CHUNK_SIZE]
struct attribute_block_s attribute_block
struct attribute_block_s attribute_block_buffer
#define sz_strlcat(dest, src)