Freeciv-3.1: /fast/freeciv/nightly/S3_1/common/networking/packets.c Source File

Freeciv-3.1

Loading...
Searching...
No Matches
packets.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12***********************************************************************/
13
14#ifdef HAVE_CONFIG_H
15#include <fc_config.h>
16#endif
17
18#include "fc_prehdrs.h"
19
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <limits.h>
24
25#ifdef HAVE_ARPA_INET_H
26#include <arpa/inet.h>
27#endif
28#ifdef HAVE_NETINET_IN_H
29#include <netinet/in.h>
30#endif
31
32/* utility */
33#include "capability.h"
34#include "fc_cmdline.h"
35#include "fcintl.h"
36#include "log.h"
37#include "mem.h"
38#include "support.h"
39
40/* common */
41#include "dataio.h"
42#include "game.h"
43#include "events.h"
44#include "map.h"
45
46#include "packets.h"
47
48#ifdef USE_COMPRESSION
49#include <zlib.h>
50/*
51 * Value for the 16bit size to indicate a jumbo packet
52 */
53#define JUMBO_SIZE 0xffff
54
55/*
56 * All values 0 <= size < COMPRESSION_BORDER are uncompressed packets.
57 */
58#define COMPRESSION_BORDER (16*1024+1)
59
60/*
61 * All compressed packets this size or greater are sent as a jumbo packet.
62 */
63#define JUMBO_BORDER (64*1024-COMPRESSION_BORDER-1)
64
65#define log_compress log_debug
66#define log_compress2 log_debug
67
68#define MAX_DECOMPRESSION 400
69
70#endif /* USE_COMPRESSION */
71
72/*
73 * Valid values are 0, 1 and 2. For 2 you have to set generate_stats
74 * to 1 in generate_packets.py.
75 */
76#define PACKET_SIZE_STATISTICS 0
77
78extern const char *const packet_functional_capability;
79
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
84#include "spechash.h"
85
86 static struct packet_handler_hash *packet_handlers = NULL;
87
88#ifdef USE_COMPRESSION
89 static int stat_size_alone = 0;
90 static int stat_size_uncompressed = 0;
91 static int stat_size_compressed = 0;
92 static int stat_size_no_compression = 0;
93
94/**********************************************************************/
97 static inline int get_compression_level(void)
98{
99 static int level = -2; /* Magic not initialized, see below. */
100
101 if (-2 == level) {
102 const char *s = getenv("FREECIV_COMPRESSION_LEVEL");
103
104 if (NULL == s || !str_to_int(s, &level) || -1 > level || 9 < level) {
105 level = -1;
106 }
107 }
108
109 return level;
110}
111
112/**********************************************************************/
115 static bool conn_compression_flush(struct connection *pconn)
116{
117 int compression_level = get_compression_level();
118 uLongf compressed_size = 12 + 1.001 * pconn->compression.queue.size;
119 Bytef compressed[compressed_size];
120 bool jumbo;
121 unsigned long compressed_packet_len;
122
123#ifndef FREECIV_NDEBUG
124 int error =
125#endif
126 compress2(compressed, &compressed_size,
127 pconn->compression.queue.p,
128 pconn->compression.queue.size,
129 compression_level);
130
131 fc_assert_ret_val(error == Z_OK, FALSE);
132
133 /* Compression signalling currently assumes a 2-byte packet length; if that
134 * changes, the protocol should probably be changed */
135 fc_assert_ret_val(data_type_size(pconn->packet_header.length) == 2, FALSE);
136
137 /* Include normal length field in decision */
138 jumbo = (compressed_size+2 >= JUMBO_BORDER);
139
140 compressed_packet_len = compressed_size + (jumbo ? 6 : 2);
141 if (compressed_packet_len < pconn->compression.queue.size) {
142 struct raw_data_out dout;
143
144 log_compress("COMPRESS: compressed %lu bytes to %ld (level %d)",
145 (unsigned long) pconn->compression.queue.size,
146 compressed_size, compression_level);
147 stat_size_uncompressed += pconn->compression.queue.size;
148 stat_size_compressed += compressed_size;
149
150 if (!jumbo) {
151 unsigned char header[2];
152
153 FC_STATIC_ASSERT(COMPRESSION_BORDER > MAX_LEN_PACKET,
154 uncompressed_compressed_packet_len_overlap);
155
156 log_compress("COMPRESS: sending %ld as normal", compressed_size);
157
158 dio_output_init(&dout, header, sizeof(header));
159 dio_put_uint16_raw(&dout, 2 + compressed_size + COMPRESSION_BORDER);
160 connection_send_data(pconn, header, sizeof(header));
161 connection_send_data(pconn, compressed, compressed_size);
162 } else {
163 unsigned char header[6];
164
165 FC_STATIC_ASSERT(JUMBO_SIZE >= JUMBO_BORDER+COMPRESSION_BORDER,
166 compressed_normal_jumbo_packet_len_overlap);
167
168 log_compress("COMPRESS: sending %ld as jumbo", compressed_size);
169 dio_output_init(&dout, header, sizeof(header));
170 dio_put_uint16_raw(&dout, JUMBO_SIZE);
171 dio_put_uint32_raw(&dout, 6 + compressed_size);
172 connection_send_data(pconn, header, sizeof(header));
173 connection_send_data(pconn, compressed, compressed_size);
174 }
175 } else {
176 log_compress("COMPRESS: would enlarge %lu bytes to %ld; "
177 "sending uncompressed",
178 (unsigned long) pconn->compression.queue.size,
179 compressed_packet_len);
180 connection_send_data(pconn, pconn->compression.queue.p,
181 pconn->compression.queue.size);
182 stat_size_no_compression += pconn->compression.queue.size;
183 }
184
185 return pconn->used;
186}
187#endif /* USE_COMPRESSION */
188
189/**********************************************************************/
194 bool conn_compression_thaw(struct connection *pconn)
195{
196#ifdef USE_COMPRESSION
197 pconn->compression.frozen_level--;
198 fc_assert_action_msg(pconn->compression.frozen_level >= 0,
199 pconn->compression.frozen_level = 0,
200 "Too many calls to conn_compression_thaw on %s!",
201 conn_description(pconn));
202 if (0 == pconn->compression.frozen_level) {
203 return conn_compression_flush(pconn);
204 }
205#endif /* USE_COMPRESSION */
206
207 return pconn->used;
208}
209
210/**********************************************************************/
213 int send_packet_data(struct connection *pc, unsigned char *data, int len,
214 enum packet_type packet_type)
215{
216 /* default for the server */
217 int result = 0;
218
219 log_packet("sending packet type=%s(%d) len=%d to %s",
220 packet_name(packet_type), packet_type, len,
221 is_server() ? pc->username : "server");
222
223 if (!is_server()) {
224 pc->client.last_request_id_used =
225 get_next_request_id(pc->client.last_request_id_used);
226 result = pc->client.last_request_id_used;
227 log_packet("sending request %d", result);
228 }
229
230 if (pc->outgoing_packet_notify) {
231 pc->outgoing_packet_notify(pc, packet_type, len, result);
232 }
233
234#ifdef USE_COMPRESSION
235 if (TRUE) {
236 int size = len;
237
238 if (conn_compression_frozen(pc)) {
239 size_t old_size;
240
241 /* Keep this a decent amount less than MAX_LEN_BUFFER to avoid the
242 * (remote) possibility of trying to dump MAX_LEN_BUFFER to the
243 * network in one go */
244#define MAX_LEN_COMPRESS_QUEUE (MAX_LEN_BUFFER/2)
245 FC_STATIC_ASSERT(MAX_LEN_COMPRESS_QUEUE < MAX_LEN_BUFFER,
246 compress_queue_maxlen_too_big);
247
248 /* If this packet would cause us to overfill the queue, flush
249 * everything that's in there already before queuing this one */
250 if (MAX_LEN_COMPRESS_QUEUE
251 < byte_vector_size(&pc->compression.queue) + len) {
252 log_compress2("COMPRESS: huge queue, forcing to flush (%lu/%lu)",
253 (long unsigned)
254 byte_vector_size(&pc->compression.queue),
255 (long unsigned) MAX_LEN_COMPRESS_QUEUE);
256 if (!conn_compression_flush(pc)) {
257 return -1;
258 }
259 byte_vector_reserve(&pc->compression.queue, 0);
260 }
261
262 old_size = byte_vector_size(&pc->compression.queue);
263 byte_vector_reserve(&pc->compression.queue, old_size + len);
264 memcpy(pc->compression.queue.p + old_size, data, len);
265 log_compress2("COMPRESS: putting %s into the queue",
266 packet_name(packet_type));
267 } else {
268 stat_size_alone += size;
269 log_compress("COMPRESS: sending %s alone (%d bytes total)",
270 packet_name(packet_type), stat_size_alone);
271 connection_send_data(pc, data, len);
272 }
273
274 log_compress2("COMPRESS: STATS: alone=%d compression-expand=%d "
275 "compression (before/after) = %d/%d",
276 stat_size_alone, stat_size_no_compression,
277 stat_size_uncompressed, stat_size_compressed);
278 }
279#else /* USE_COMPRESSION */
280 connection_send_data(pc, data, len);
281#endif /* USE_COMPRESSION */
282
283#if PACKET_SIZE_STATISTICS
284 {
285 static struct {
286 int counter;
287 int size;
288 } packets_stats[PACKET_LAST];
289 static int packet_counter = 0;
290 static int last_start_turn_seen = -1;
291 static bool start_turn_seen = FALSE;
292
293 int size = len;
294 bool print = FALSE;
295 bool clear = FALSE;
296
297 if (!packet_counter) {
298 int i;
299
300 for (i = 0; i < PACKET_LAST; i++) {
301 packets_stats[i].counter = 0;
302 packets_stats[i].size = 0;
303 }
304 }
305
306 packets_stats[packet_type].counter++;
307 packets_stats[packet_type].size += size;
308
309 packet_counter++;
310 if (packet_type == PACKET_START_TURN
311 && last_start_turn_seen != game.turn) {
312 start_turn_seen = TRUE;
313 last_start_turn_seen = game.turn;
314 }
315
316 if ((packet_type ==
317 PACKET_PROCESSING_FINISHED || packet_type == PACKET_THAW_HINT)
318 && start_turn_seen) {
319 start_turn_seen = FALSE;
320 print = TRUE;
321 clear = TRUE;
322 }
323
324 if (print) {
325 int i, sum = 0;
326#define log_ll log_debug
327
328#if PACKET_SIZE_STATISTICS == 2
329 delta_stats_report();
330#endif
331 log_ll("Transmitted packets:");
332 log_ll("%8s %8s %8s %s", "Packets", "Bytes", "Byt/Pac", "Name");
333
334 for (i = 0; i < PACKET_LAST; i++) {
335 if (packets_stats[i].counter == 0) {
336 continue;
337 }
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,
342 packet_name(i),i);
343 }
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);
347 log_test("turn=%d; transmitted %d bytes", game.turn,
348 pc->statistics.bytes_send);
349 }
350 if (clear) {
351 int i;
352
353 for (i = 0; i < PACKET_LAST; i++) {
354 packets_stats[i].counter = 0;
355 packets_stats[i].size = 0;
356 }
357 packet_counter = 0;
358 pc->statistics.bytes_send = 0;
359 delta_stats_reset();
360 }
361 }
362#undef log_ll
363#endif /* PACKET_SIZE_STATISTICS */
364
365 return result;
366}
367
368/**********************************************************************/
373 void *get_packet_from_connection_raw(struct connection *pc,
374 enum packet_type *ptype)
375{
376 int len_read;
377 int whole_packet_len;
378 struct {
379 enum packet_type type;
380 int itype;
381 } utype;
382 struct data_in din;
383#ifdef USE_COMPRESSION
384 bool compressed_packet = FALSE;
385 int header_size = 0;
386#endif
387 void *data;
388 void *(*receive_handler)(struct connection *);
389
390 if (!pc->used) {
391 return NULL; /* connection was closed, stop reading */
392 }
393
394 if (pc->buffer->ndata < data_type_size(pc->packet_header.length)) {
395 /* Not got enough for a length field yet */
396 return NULL;
397 }
398
399 dio_input_init(&din, pc->buffer->data, pc->buffer->ndata);
400 dio_get_type_raw(&din, pc->packet_header.length, &len_read);
401
402 /* The non-compressed case */
403 whole_packet_len = len_read;
404
405#ifdef USE_COMPRESSION
406 /* Compression signalling currently assumes a 2-byte packet length; if that
407 * changes, the protocol should probably be changed */
408 fc_assert(data_type_size(pc->packet_header.length) == 2);
409 if (len_read == JUMBO_SIZE) {
410 compressed_packet = TRUE;
411 header_size = 6;
412 if (dio_input_remaining(&din) >= 4) {
413 dio_get_uint32_raw(&din, &whole_packet_len);
414 log_compress("COMPRESS: got a jumbo packet of size %d",
415 whole_packet_len);
416 } else {
417 /* to return NULL below */
418 whole_packet_len = 6;
419 }
420 } else if (len_read >= COMPRESSION_BORDER) {
421 compressed_packet = TRUE;
422 header_size = 2;
423 whole_packet_len = len_read - COMPRESSION_BORDER;
424 log_compress("COMPRESS: got a normal packet of size %d",
425 whole_packet_len);
426 }
427#endif /* USE_COMPRESSION */
428
429 if ((unsigned)whole_packet_len > pc->buffer->ndata) {
430 return NULL; /* not all data has been read */
431 }
432
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.");
437 connection_close(pc, _("illegal packet size"));
438
439 return NULL;
440 }
441
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;
447 struct socket_packet_buffer *buffer = pc->buffer;
448 void *decompressed = fc_malloc(decompressed_size);
449
450 do {
451 error =
452 uncompress(decompressed, &decompressed_size,
453 ADD_TO_POINTER(buffer->data, header_size),
454 compressed_size);
455
456 if (error == Z_BUF_ERROR) {
457 decompress_factor += 50;
458 decompressed_size = decompress_factor * compressed_size;
459 decompressed = fc_realloc(decompressed, decompressed_size);
460 }
461
462 if (error != Z_OK) {
463 if (error != Z_BUF_ERROR || decompress_factor > MAX_DECOMPRESSION ) {
464 log_verbose("Uncompressing of the packet stream failed. "
465 "The connection will be closed now.");
466 connection_close(pc, _("decoding error"));
467 return NULL;
468 }
469 }
470
471 } while (error != Z_OK);
472
473 buffer->ndata -= whole_packet_len;
474 /*
475 * Remove the packet with the compressed data and shift all the
476 * remaining data to the front.
477 */
478 memmove(buffer->data, buffer->data + whole_packet_len, buffer->ndata);
479
480 if (buffer->ndata + decompressed_size > buffer->nsize) {
481 buffer->nsize += decompressed_size;
482 buffer->data = fc_realloc(buffer->data, buffer->nsize);
483 }
484
485 /*
486 * Make place for the uncompressed data by moving the remaining
487 * data.
488 */
489 memmove(buffer->data + decompressed_size, buffer->data, buffer->ndata);
490
491 /*
492 * Copy the uncompressed data.
493 */
494 memcpy(buffer->data, decompressed, decompressed_size);
495
496 free(decompressed);
497
498 buffer->ndata += decompressed_size;
499
500 log_compress("COMPRESS: decompressed %ld into %ld",
501 compressed_size, decompressed_size);
502
503 return get_packet_from_connection(pc, ptype);
504 }
505#endif /* USE_COMPRESSION */
506
507 /*
508 * At this point the packet is a plain uncompressed one. These have
509 * to have to be at least the header bytes in size.
510 */
511 if (whole_packet_len < (data_type_size(pc->packet_header.length)
512 + data_type_size(pc->packet_header.type))) {
513 log_verbose("The packet stream is corrupt. The connection "
514 "will be closed now.");
515 connection_close(pc, _("decoding error"));
516 return NULL;
517 }
518
519 dio_get_type_raw(&din, pc->packet_header.type, &utype.itype);
520 utype.type = utype.itype;
521
522 if (utype.type >= PACKET_LAST
523 || (receive_handler = pc->phs.handlers->receive[utype.type]) == NULL) {
524 log_verbose("Received unsupported packet type %d (%s). The connection "
525 "will be closed now.",
526 utype.type, packet_name(utype.type));
527 connection_close(pc, _("unsupported packet type"));
528 return NULL;
529 }
530
531 log_packet("got packet type=(%s)%d len=%d from %s",
532 packet_name(utype.type), utype.itype, whole_packet_len,
533 is_server() ? pc->username : "server");
534
535 *ptype = utype.type;
536
537 if (pc->incoming_packet_notify) {
538 pc->incoming_packet_notify(pc, utype.type, whole_packet_len);
539 }
540
541#if PACKET_SIZE_STATISTICS
542 {
543 static struct {
544 int counter;
545 int size;
546 } packets_stats[PACKET_LAST];
547 static int packet_counter = 0;
548
549 int packet_type = utype.itype;
550 int size = whole_packet_len;
551
552 if (!packet_counter) {
553 int i;
554
555 for (i = 0; i < PACKET_LAST; i++) {
556 packets_stats[i].counter = 0;
557 packets_stats[i].size = 0;
558 }
559 }
560
561 packets_stats[packet_type].counter++;
562 packets_stats[packet_type].size += size;
563
564 packet_counter++;
565 if (packet_counter % 100 == 0) {
566 int i, sum = 0;
567
568 log_test("Received packets:");
569 for (i = 0; i < PACKET_LAST; i++) {
570 if (packets_stats[i].counter == 0) {
571 continue;
572 }
573 sum += packets_stats[i].size;
574 log_test(" [%-25.25s %3d]: %6d packets; %8d bytes total; "
575 "%5d bytes/packet average",
576 packet_name(i), i, packets_stats[i].counter,
577 packets_stats[i].size,
578 packets_stats[i].size / packets_stats[i].counter);
579 }
580 log_test("received %d bytes in %d packets;average size "
581 "per packet %d bytes",
582 sum, packet_counter, sum / packet_counter);
583 }
584 }
585#endif /* PACKET_SIZE_STATISTICS */
586 data = receive_handler(pc);
587 if (!data) {
588 connection_close(pc, _("incompatible packet contents"));
589 return NULL;
590 } else {
591 return data;
592 }
593}
594
595/**********************************************************************/
598 void remove_packet_from_buffer(struct socket_packet_buffer *buffer)
599{
600 struct data_in din;
601 int len;
602
603 dio_input_init(&din, buffer->data, buffer->ndata);
604 dio_get_uint16_raw(&din, &len);
605 memmove(buffer->data, buffer->data + len, buffer->ndata - len);
606 buffer->ndata -= len;
607 log_debug("remove_packet_from_buffer: remove %d; remaining %d",
608 len, buffer->ndata);
609}
610
611/**********************************************************************/
617 void packet_header_init(struct packet_header *packet_header)
618{
619 packet_header->length = DIOT_UINT16;
620 packet_header->type = DIOT_UINT8;
621}
622
623/**********************************************************************/
627 static inline void packet_header_set(struct packet_header *packet_header)
628{
629 /* Ensure we have values initialized in packet_header_init(). */
630 fc_assert(packet_header->length == DIOT_UINT16);
631 fc_assert(packet_header->type == DIOT_UINT8);
632
633 packet_header->length = DIOT_UINT16;
634 packet_header->type = DIOT_UINT16;
635}
636
637/**********************************************************************/
640 void post_send_packet_server_join_reply(struct connection *pconn,
641 const struct packet_server_join_reply
642 *packet)
643{
644 if (packet->you_can_join) {
645 packet_header_set(&pconn->packet_header);
646 }
647}
648
649/**********************************************************************/
652 void post_receive_packet_server_join_reply(struct connection *pconn,
653 const struct
654 packet_server_join_reply *packet)
655{
656 if (packet->you_can_join) {
657 packet_header_set(&pconn->packet_header);
658 }
659}
660
661
662/**********************************************************************/
665 bool packet_check(struct data_in *din, struct connection *pc)
666{
667 size_t rem = dio_input_remaining(din);
668
669 if (rem > 0) {
670 int type, len;
671
672 dio_input_rewind(din);
673 dio_get_type_raw(din, pc->packet_header.length, &len);
674 dio_get_type_raw(din, pc->packet_header.type, &type);
675
676 log_packet("received long packet (type %d, len %d, rem %lu) from %s",
677 type,
678 len,
679 (unsigned long) rem,
680 conn_description (pc));
681 return FALSE;
682 }
683
684 return TRUE;
685}
686
687/**********************************************************************/
690 void generic_handle_player_attribute_chunk(struct player *pplayer,
691 const struct
692 packet_player_attribute_chunk
693 *chunk)
694{
695 log_packet("received attribute chunk %u/%u %u",
696 (unsigned int) chunk->offset,
697 (unsigned int) chunk->total_length,
698 (unsigned int) chunk->chunk_length);
699
700 if (chunk->total_length < 0
701 || chunk->chunk_length < 0
702 || chunk->total_length >= MAX_ATTRIBUTE_BLOCK
703 || chunk->offset < 0
704 || chunk->offset > chunk->total_length /* necessary check on 32 bit systems */
705 || chunk->chunk_length > chunk->total_length
706 || chunk->offset + chunk->chunk_length > chunk->total_length
707 || (chunk->offset != 0
708 && chunk->total_length != pplayer->attribute_block_buffer.length)) {
709 /* wrong attribute data */
710 if (pplayer->attribute_block_buffer.data) {
711 free(pplayer->attribute_block_buffer.data);
712 pplayer->attribute_block_buffer.data = NULL;
713 }
714 pplayer->attribute_block_buffer.length = 0;
715 log_error("Received wrong attribute chunk");
716 return;
717 }
718 /* first one in a row */
719 if (chunk->offset == 0) {
720 if (pplayer->attribute_block_buffer.data) {
721 free(pplayer->attribute_block_buffer.data);
722 pplayer->attribute_block_buffer.data = NULL;
723 }
724 pplayer->attribute_block_buffer.data = fc_malloc(chunk->total_length);
725 pplayer->attribute_block_buffer.length = chunk->total_length;
726 }
727 memcpy((char *) (pplayer->attribute_block_buffer.data) + chunk->offset,
728 chunk->data, chunk->chunk_length);
729
730 if (chunk->offset + chunk->chunk_length == chunk->total_length) {
731 /* Received full attribute block */
732 if (pplayer->attribute_block.data != NULL) {
733 free(pplayer->attribute_block.data);
734 }
735 pplayer->attribute_block.data = pplayer->attribute_block_buffer.data;
736 pplayer->attribute_block.length = pplayer->attribute_block_buffer.length;
737
738 pplayer->attribute_block_buffer.data = NULL;
739 pplayer->attribute_block_buffer.length = 0;
740 }
741}
742
743/**********************************************************************/
746 void send_attribute_block(const struct player *pplayer,
747 struct connection *pconn)
748{
749 struct packet_player_attribute_chunk packet;
750 int current_chunk, chunks, bytes_left;
751
752 if (!pplayer || !pplayer->attribute_block.data) {
753 return;
754 }
755
756 fc_assert_ret(pplayer->attribute_block.length > 0
757 && pplayer->attribute_block.length < MAX_ATTRIBUTE_BLOCK);
758
759 chunks =
760 (pplayer->attribute_block.length - 1) / ATTRIBUTE_CHUNK_SIZE + 1;
761 bytes_left = pplayer->attribute_block.length;
762
763 connection_do_buffer(pconn);
764
765 for (current_chunk = 0; current_chunk < chunks; current_chunk++) {
766 int size_of_current_chunk = MIN(bytes_left, ATTRIBUTE_CHUNK_SIZE);
767
768 packet.offset = ATTRIBUTE_CHUNK_SIZE * current_chunk;
769 packet.total_length = pplayer->attribute_block.length;
770 packet.chunk_length = size_of_current_chunk;
771
772 memcpy(packet.data,
773 (char *) (pplayer->attribute_block.data) + packet.offset,
774 packet.chunk_length);
775 bytes_left -= packet.chunk_length;
776
777 if (packet.chunk_length < ATTRIBUTE_CHUNK_SIZE) {
778 /* Last chunk is not full. Make sure that delta does
779 * not use random data. */
780 memset(packet.data + packet.chunk_length, 0,
781 ATTRIBUTE_CHUNK_SIZE - packet.chunk_length);
782 }
783
784 send_packet_player_attribute_chunk(pconn, &packet);
785 }
786
787 connection_do_unbuffer(pconn);
788}
789
790/**********************************************************************/
793 void pre_send_packet_player_attribute_chunk(struct connection *pc,
794 struct packet_player_attribute_chunk
795 *packet)
796{
797 fc_assert(packet->total_length > 0
798 && packet->total_length < MAX_ATTRIBUTE_BLOCK);
799 /* 500 bytes header, just to be sure */
800 fc_assert(packet->chunk_length > 0
801 && packet->chunk_length < MAX_LEN_PACKET - 500);
802 fc_assert(packet->chunk_length <= packet->total_length);
803 fc_assert(packet->offset >= 0 && packet->offset < packet->total_length);
804
805 log_packet("sending attribute chunk %d/%d %d",
806 packet->offset, packet->total_length, packet->chunk_length);
807}
808
809/**********************************************************************/
812 static void packet_handlers_free(void)
813{
814 if (packet_handlers != NULL) {
815 packet_handler_hash_destroy(packet_handlers);
816 packet_handlers = NULL;
817 }
818}
819
820/**********************************************************************/
823 const struct packet_handlers *packet_handlers_initial(void)
824{
825 static struct packet_handlers default_handlers;
826 static bool initialized = FALSE;
827
828 if (!initialized) {
829 memset(&default_handlers, 0, sizeof(default_handlers));
830 packet_handlers_fill_initial(&default_handlers);
831 initialized = TRUE;
832 }
833
834 return &default_handlers;
835}
836
837/**********************************************************************/
840 const struct packet_handlers *packet_handlers_get(const char *capability)
841{
842 struct packet_handlers *phandlers;
843 char functional_capability[MAX_LEN_CAPSTR] = "";
844 char *tokens[MAX_LEN_CAPSTR / 2];
845 char *functional_tokens[MAX_LEN_CAPSTR / 2];
846 int tokens_num;
847 int functional_tokens_num = 0;
848 int i;
849
850 fc_assert(strlen(capability) < sizeof(functional_capability));
851
852 /* Get functional network capability string. */
853 tokens_num = get_tokens(capability, tokens, ARRAY_SIZE(tokens), " \t\n,");
854 for (i = 0; i < tokens_num; i++) {
855 char *token;
856
857 token = tokens[i];
858 if (token[0] == '+') {
859 token++;
860 }
861
862 if (has_capability(token, packet_functional_capability)) {
863 functional_tokens[functional_tokens_num++] = token;
864 }
865 }
866 qsort(functional_tokens, functional_tokens_num,
867 sizeof(*functional_tokens), compare_strings_ptrs);
868 for (i = 0; i < functional_tokens_num; i++) {
869 if (functional_capability[0] != '\0') {
870 sz_strlcat(functional_capability, " ");
871 }
872 sz_strlcat(functional_capability, functional_tokens[i]);
873 }
874 free_tokens(tokens, tokens_num);
875
876 /* Ensure the hash table is created. */
877 if (packet_handlers == NULL) {
878 packet_handlers = packet_handler_hash_new();
879 }
880
881 /* Lookup handlers for the capabilities or create new handlers. */
882 if (!packet_handler_hash_lookup(packet_handlers, functional_capability,
883 &phandlers)) {
884 phandlers = fc_malloc(sizeof(*phandlers));
885 memcpy(phandlers, packet_handlers_initial(), sizeof(*phandlers));
886 packet_handlers_fill_capability(phandlers, functional_capability);
887 packet_handler_hash_insert(packet_handlers, functional_capability,
888 phandlers);
889 }
890
891 fc_assert(phandlers != NULL);
892
893 return phandlers;
894}
895
896/**********************************************************************/
900 void packets_deinit(void)
901{
902 packet_handlers_free();
903}
has_capability
bool has_capability(const char *cap, const char *capstr)
Definition capability.c:77
capability.h
get_next_request_id
int get_next_request_id(int old_request_id)
Definition connection.c:529
connection_do_buffer
void connection_do_buffer(struct connection *pc)
Definition connection.c:323
connection_close
void connection_close(struct connection *pconn, const char *reason)
Definition connection.c:88
conn_description
const char * conn_description(const struct connection *pconn)
Definition connection.c:473
connection_send_data
bool connection_send_data(struct connection *pconn, const unsigned char *data, int len)
Definition connection.c:286
conn_compression_frozen
bool conn_compression_frozen(const struct connection *pconn)
Definition connection.c:705
connection_do_unbuffer
void connection_do_unbuffer(struct connection *pc)
Definition connection.c:335
MAX_LEN_PACKET
#define MAX_LEN_PACKET
Definition connection.h:56
MAX_LEN_BUFFER
#define MAX_LEN_BUFFER
Definition connection.h:61
MAX_LEN_CAPSTR
#define MAX_LEN_CAPSTR
Definition connection.h:57
dataio.h
dio_output_init
void dio_output_init(struct raw_data_out *dout, void *destination, size_t dest_size)
Definition dataio_raw.c:171
dio_put_uint16_raw
void dio_put_uint16_raw(struct raw_data_out *dout, int value)
Definition dataio_raw.c:284
dio_input_remaining
size_t dio_input_remaining(struct data_in *din)
Definition dataio_raw.c:221
dio_get_uint32_raw
bool dio_get_uint32_raw(struct data_in *din, int *dest)
Definition dataio_raw.c:614
dio_input_rewind
void dio_input_rewind(struct data_in *din)
Definition dataio_raw.c:213
dio_put_uint32_raw
void dio_put_uint32_raw(struct raw_data_out *dout, int value)
Definition dataio_raw.c:303
dio_get_uint16_raw
bool dio_get_uint16_raw(struct data_in *din, int *dest)
Definition dataio_raw.c:593
dio_get_type_raw
bool dio_get_type_raw(struct data_in *din, enum data_type type, int *dest)
Definition dataio_raw.c:635
data_type_size
size_t data_type_size(enum data_type type)
Definition dataio_raw.c:229
dio_input_init
void dio_input_init(struct data_in *din, const void *src, size_t src_size)
Definition dataio_raw.c:202
DIOT_UINT8
@ DIOT_UINT8
Definition dataio_raw.h:44
DIOT_UINT16
@ DIOT_UINT16
Definition dataio_raw.h:45
initialized
static bool initialized
Definition effects.c:42
events.h
free_tokens
void free_tokens(char **tokens, size_t ntokens)
Definition fc_cmdline.c:203
get_tokens
int get_tokens(const char *str, char **tokens, size_t num_tokens, const char *delimiterset)
Definition fc_cmdline.c:166
fc_cmdline.h
is_server
static bool is_server(void)
Definition fc_interface.h:69
fc_prehdrs.h
fcintl.h
_
#define _(String)
Definition fcintl.h:67
game
struct civ_game game
Definition game.c:57
game.h
type
GType type
Definition repodlgs.c:1312
log.h
fc_assert_ret
#define fc_assert_ret(condition)
Definition log.h:191
log_packet
#define log_packet
Definition log.h:137
log_test
#define log_test
Definition log.h:136
log_verbose
#define log_verbose(message,...)
Definition log.h:109
fc_assert
#define fc_assert(condition)
Definition log.h:176
fc_assert_action_msg
#define fc_assert_action_msg(condition, action, message,...)
Definition log.h:201
fc_assert_ret_val
#define fc_assert_ret_val(condition, val)
Definition log.h:194
log_debug
#define log_debug(message,...)
Definition log.h:115
log_error
#define log_error(message,...)
Definition log.h:103
FC_STATIC_ASSERT
#define FC_STATIC_ASSERT(cond, tag)
Definition log.h:235
map.h
mem.h
fc_realloc
#define fc_realloc(ptr, sz)
Definition mem.h:36
fc_malloc
#define fc_malloc(sz)
Definition mem.h:34
log_compress2
#define log_compress2
Definition packets.c:66
post_receive_packet_server_join_reply
void post_receive_packet_server_join_reply(struct connection *pconn, const struct packet_server_join_reply *packet)
Definition packets.c:652
packet_handlers_free
static void packet_handlers_free(void)
Definition packets.c:812
COMPRESSION_BORDER
#define COMPRESSION_BORDER
Definition packets.c:58
get_packet_from_connection_raw
void * get_packet_from_connection_raw(struct connection *pc, enum packet_type *ptype)
Definition packets.c:373
MAX_DECOMPRESSION
#define MAX_DECOMPRESSION
Definition packets.c:68
packet_check
bool packet_check(struct data_in *din, struct connection *pc)
Definition packets.c:665
packet_header_init
void packet_header_init(struct packet_header *packet_header)
Definition packets.c:617
conn_compression_thaw
bool conn_compression_thaw(struct connection *pconn)
Definition packets.c:194
packet_handlers_initial
const struct packet_handlers * packet_handlers_initial(void)
Definition packets.c:823
packet_functional_capability
const char *const packet_functional_capability
Definition packets_gen.c:32
packets_deinit
void packets_deinit(void)
Definition packets.c:900
pre_send_packet_player_attribute_chunk
void pre_send_packet_player_attribute_chunk(struct connection *pc, struct packet_player_attribute_chunk *packet)
Definition packets.c:793
JUMBO_BORDER
#define JUMBO_BORDER
Definition packets.c:63
packet_header_set
static void packet_header_set(struct packet_header *packet_header)
Definition packets.c:627
stat_size_compressed
static int stat_size_compressed
Definition packets.c:91
get_compression_level
static int get_compression_level(void)
Definition packets.c:97
remove_packet_from_buffer
void remove_packet_from_buffer(struct socket_packet_buffer *buffer)
Definition packets.c:598
post_send_packet_server_join_reply
void post_send_packet_server_join_reply(struct connection *pconn, const struct packet_server_join_reply *packet)
Definition packets.c:640
JUMBO_SIZE
#define JUMBO_SIZE
Definition packets.c:53
stat_size_uncompressed
static int stat_size_uncompressed
Definition packets.c:90
send_packet_data
int send_packet_data(struct connection *pc, unsigned char *data, int len, enum packet_type packet_type)
Definition packets.c:213
MAX_LEN_COMPRESS_QUEUE
#define MAX_LEN_COMPRESS_QUEUE
stat_size_alone
static int stat_size_alone
Definition packets.c:89
generic_handle_player_attribute_chunk
void generic_handle_player_attribute_chunk(struct player *pplayer, const struct packet_player_attribute_chunk *chunk)
Definition packets.c:690
stat_size_no_compression
static int stat_size_no_compression
Definition packets.c:92
send_attribute_block
void send_attribute_block(const struct player *pplayer, struct connection *pconn)
Definition packets.c:746
packet_handlers_get
const struct packet_handlers * packet_handlers_get(const char *capability)
Definition packets.c:840
conn_compression_flush
static bool conn_compression_flush(struct connection *pconn)
Definition packets.c:115
log_compress
#define log_compress
Definition packets.c:65
packets.h
ATTRIBUTE_CHUNK_SIZE
#define ATTRIBUTE_CHUNK_SIZE
Definition packets.h:65
get_packet_from_connection
#define get_packet_from_connection(pc, ptype)
Definition packets.h:113
packet_handlers_fill_capability
void packet_handlers_fill_capability(struct packet_handlers *phandlers, const char *capability)
Definition packets_gen.c:95970
packet_name
const char * packet_name(enum packet_type type)
Definition packets_gen.c:49
packet_handlers_fill_initial
void packet_handlers_fill_initial(struct packet_handlers *phandlers)
Definition packets_gen.c:95655
delta_stats_reset
void delta_stats_reset(void)
Definition packets_gen.c:47
delta_stats_report
void delta_stats_report(void)
Definition packets_gen.c:45
send_packet_player_attribute_chunk
int send_packet_player_attribute_chunk(struct connection *pc, const struct packet_player_attribute_chunk *packet)
Definition packets_gen.c:36070
packet_type
packet_type
Definition packets_gen.h:1883
PACKET_LAST
@ PACKET_LAST
Definition packets_gen.h:2078
PACKET_PROCESSING_FINISHED
@ PACKET_PROCESSING_FINISHED
Definition packets_gen.h:1885
len
int len
Definition packhand.c:125
MAX_ATTRIBUTE_BLOCK
#define MAX_ATTRIBUTE_BLOCK
Definition player.h:225
level
struct setting_list * level[OLEVELS_NUM]
Definition settings.c:183
compare_strings_ptrs
int compare_strings_ptrs(const void *first, const void *second)
Definition shared.c:368
str_to_int
bool str_to_int(const char *str, int *pint)
Definition shared.c:512
ADD_TO_POINTER
#define ADD_TO_POINTER(p, n)
Definition shared.h:86
ARRAY_SIZE
#define ARRAY_SIZE(x)
Definition shared.h:85
MIN
#define MIN(x, y)
Definition shared.h:55
spechash.h
size
size_t size
Definition specvec.h:72
attribute_block_s::data
void * data
Definition player.h:223
attribute_block_s::length
int length
Definition player.h:224
connection
Definition connection.h:141
connection::statistics
struct connection::@61 statistics
connection::client
struct connection::@57::@62 client
connection::handlers
const struct packet_handlers * handlers
Definition connection.h:267
connection::last_request_id_used
int last_request_id_used
Definition connection.h:192
connection::phs
struct connection::@59 phs
connection::packet_header
struct packet_header packet_header
Definition connection.h:146
connection::username
char username[MAX_LEN_NAME]
Definition connection.h:169
connection::compression
struct connection::@60 compression
connection::incoming_packet_notify
void(* incoming_packet_notify)(struct connection *pc, int packet_type, int size)
Definition connection.h:253
connection::bytes_send
int bytes_send
Definition connection.h:278
connection::outgoing_packet_notify
void(* outgoing_packet_notify)(struct connection *pc, int packet_type, int size, int request_id)
Definition connection.h:261
connection::queue
struct byte_vector queue
Definition connection.h:274
connection::frozen_level
int frozen_level
Definition connection.h:272
connection::buffer
struct socket_packet_buffer * buffer
Definition connection.h:158
connection::used
bool used
Definition connection.h:144
data_in
Definition dataio_raw.h:30
packet_handlers
Definition packets.h:97
packet_handlers::receive
void *(* receive[PACKET_LAST])(struct connection *pconn)
Definition packets.h:104
packet_header
Definition connection.h:128
packet_header::length
unsigned int length
Definition connection.h:129
packet_header::type
unsigned int type
Definition connection.h:130
packet_player_attribute_chunk
Definition packets_gen.h:591
packet_player_attribute_chunk::chunk_length
int chunk_length
Definition packets_gen.h:594
packet_player_attribute_chunk::data
unsigned char data[ATTRIBUTE_CHUNK_SIZE]
Definition packets_gen.h:595
packet_player_attribute_chunk::total_length
int total_length
Definition packets_gen.h:593
packet_player_attribute_chunk::offset
int offset
Definition packets_gen.h:592
packet_server_join_reply
Definition packets_gen.h:54
packet_server_join_reply::you_can_join
bool you_can_join
Definition packets_gen.h:55
player
Definition player.h:249
player::attribute_block
struct attribute_block_s attribute_block
Definition player.h:303
player::attribute_block_buffer
struct attribute_block_s attribute_block_buffer
Definition player.h:304
raw_data_out
Definition dataio_raw.h:35
socket_packet_buffer
Definition connection.h:121
socket_packet_buffer::ndata
int ndata
Definition connection.h:122
socket_packet_buffer::nsize
int nsize
Definition connection.h:124
socket_packet_buffer::data
unsigned char * data
Definition connection.h:125
support.h
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47
sz_strlcat
#define sz_strlcat(dest, src)
Definition support.h:162