Freeciv21
Develop your civilization from humble roots to a global empire
packets.cpp
Go to the documentation of this file.
1 /*__ ___ ***************************************
2 / \ / \ Copyright (c) 1996-2020 Freeciv21 and Freeciv
3 \_ \ / __/ contributors. This file is part of Freeciv21.
4  _\ \ / /__ Freeciv21 is free software: you can redistribute it
5  \___ \____/ __/ and/or modify it under the terms of the GNU General
6  \_ _/ Public License as published by the Free Software
7  | @ @ \_ Foundation, either version 3 of the License,
8  | or (at your option) any later version.
9  _/ /\ You should have received a copy of the GNU
10  /o) (o/\ \_ General Public License along with Freeciv21.
11  \_____/ / If not, see https://www.gnu.org/licenses/.
12  \____/ ********************************************************/
13 
14 #include <cstring>
15 
16 // utility
17 #include "capability.h"
18 #include "connection.h"
19 #include "fcintl.h"
20 #include "log.h"
21 #include "support.h"
22 
23 // commmon
24 #include "dataio.h"
25 #include "game.h"
26 #include "packets.h"
27 
28 #include <QRegularExpression>
29 
30 #include <zlib.h>
31 /*
32  * Value for the 16bit size to indicate a jumbo packet
33  */
34 #define JUMBO_SIZE 0xffff
35 
36 /*
37  * All values 0<=size<COMPRESSION_BORDER are uncompressed packets.
38  */
39 #define COMPRESSION_BORDER (16 * 1024 + 1)
40 #define PACKET_STRVEC_SEPARATOR '\3'
41 /*
42  * All compressed packets this size or greater are sent as a jumbo packet.
43  */
44 #define JUMBO_BORDER (64 * 1024 - COMPRESSION_BORDER - 1)
45 
46 #define log_compress log_debug
47 #define log_compress2 log_debug
48 
49 #define MAX_DECOMPRESSION 400
50 
51 /*
52  * Valid values are 0, 1 and 2. For 2 you have to set generate_stats
53  * to 1 in generate_packets.py.
54  */
55 #define PACKET_SIZE_STATISTICS 0
56 
57 extern "C" const char *const packet_functional_capability;
58 
59 typedef QHash<QString, struct packet_handlers *> packetsHash;
60 Q_GLOBAL_STATIC(packetsHash, packet_handlers_hash)
61 
62 static int stat_size_alone = 0;
63 static int stat_size_uncompressed = 0;
64 static int stat_size_compressed = 0;
65 static int stat_size_no_compression = 0;
66 
70 static inline int get_compression_level()
71 {
72  static int level = -2; // Magic not initialized, see below.
73 
74  if (-2 == level) {
75  const char *s = getenv("FREECIV_COMPRESSION_LEVEL");
76 
77  if (nullptr == s || !str_to_int(s, &level) || -1 > level || 9 < level) {
78  level = -1;
79  }
80  }
81 
82  return level;
83 }
84 
88 static bool conn_compression_flush(struct connection *pconn)
89 {
90  int compression_level = get_compression_level();
91  uLongf compressed_size = 12 + 1.001 * pconn->compression.queue.size;
92  int error;
93  QScopedArrayPointer<Bytef> compressed(new Bytef[compressed_size]);
94  bool jumbo;
95  unsigned long compressed_packet_len;
96 
97  error = compress2(compressed.data(), &compressed_size,
98  pconn->compression.queue.p,
99  pconn->compression.queue.size, compression_level);
100  fc_assert_ret_val(error == Z_OK, false);
101 
102  /* Compression signalling currently assumes a 2-byte packet length; if that
103  * changes, the protocol should probably be changed */
105  data_type_size(data_type(pconn->packet_header.length)) == 2, false);
106 
107  // Include normal length field in decision
108  jumbo = (compressed_size + 2 >= JUMBO_BORDER);
109 
110  compressed_packet_len = compressed_size + (jumbo ? 6 : 2);
111  if (compressed_packet_len < pconn->compression.queue.size) {
112  struct raw_data_out dout;
113 
114  log_compress("COMPRESS: compressed %lu bytes to %ld (level %d)",
115  (unsigned long) pconn->compression.queue.size,
116  compressed_size, compression_level);
118  stat_size_compressed += compressed_size;
119 
120  if (!jumbo) {
121  unsigned char header[2];
123  uncompressed_compressed_packet_len_overlap);
124 
125  log_compress("COMPRESS: sending %ld as normal", compressed_size);
126 
127  dio_output_init(&dout, header, sizeof(header));
128  dio_put_uint16_raw(&dout, 2 + compressed_size + COMPRESSION_BORDER);
129  connection_send_data(pconn, header, sizeof(header));
130  connection_send_data(pconn, compressed.data(), compressed_size);
131  } else {
132  unsigned char header[6];
134  compressed_normal_jumbo_packet_len_overlap);
135 
136  log_compress("COMPRESS: sending %ld as jumbo", compressed_size);
137  dio_output_init(&dout, header, sizeof(header));
139  dio_put_uint32_raw(&dout, 6 + compressed_size);
140  connection_send_data(pconn, header, sizeof(header));
141  connection_send_data(pconn, compressed.data(), compressed_size);
142  }
143  } else {
144  log_compress("COMPRESS: would enlarge %lu bytes to %ld; "
145  "sending uncompressed",
146  (unsigned long) pconn->compression.queue.size,
147  compressed_packet_len);
148  connection_send_data(pconn, pconn->compression.queue.p,
149  pconn->compression.queue.size);
151  }
152  return pconn->used;
153 }
154 
161 {
162  pconn->compression.frozen_level--;
164  pconn->compression.frozen_level = 0,
165  "Too many calls to conn_compression_thaw on %s!",
166  conn_description(pconn));
167  if (0 == pconn->compression.frozen_level) {
168  return conn_compression_flush(pconn);
169  }
170  return pconn->used;
171 }
172 
176 int send_packet_data(struct connection *pc, unsigned char *data, int len,
177  enum packet_type packet_type)
178 {
179  // default for the server
180  int result = 0;
181 
182  log_packet("sending packet type=%s(%d) len=%d to %s",
183  packet_name(packet_type), packet_type, len,
184  is_server() ? pc->username : "server");
185 
186  if (!is_server()) {
187  pc->client.last_request_id_used =
188  get_next_request_id(pc->client.last_request_id_used);
189  result = pc->client.last_request_id_used;
190  log_packet("sending request %d", result);
191  }
192 
193  if (pc->outgoing_packet_notify) {
194  pc->outgoing_packet_notify(pc, packet_type, len, result);
195  }
196 
197  int size = len;
198  if (conn_compression_frozen(pc)) {
199  size_t old_size;
200 
201  /* Keep this a decent amount less than MAX_LEN_BUFFER to avoid the
202  * (remote) possibility of trying to dump MAX_LEN_BUFFER to the
203  * network in one go */
204 #define MAX_LEN_COMPRESS_QUEUE (MAX_LEN_BUFFER / 2)
206  compress_queue_maxlen_too_big);
207 
208  /* If this packet would cause us to overfill the queue, flush
209  * everything that's in there already before queuing this one */
211  < byte_vector_size(&pc->compression.queue) + len) {
212  log_compress2("COMPRESS: huge queue, forcing to flush (%lu/%lu)",
213  (long unsigned) byte_vector_size(&pc->compression.queue),
214  (long unsigned) MAX_LEN_COMPRESS_QUEUE);
215  if (!conn_compression_flush(pc)) {
216  return -1;
217  }
218  byte_vector_reserve(&pc->compression.queue, 0);
219  }
220 
221  old_size = byte_vector_size(&pc->compression.queue);
222  byte_vector_reserve(&pc->compression.queue, old_size + len);
223  memcpy(pc->compression.queue.p + old_size, data, len);
224  log_compress2("COMPRESS: putting %s into the queue",
225  packet_name(packet_type));
226  } else {
228  log_compress("COMPRESS: sending %s alone (%d bytes total)",
229  packet_name(packet_type), stat_size_alone);
230  connection_send_data(pc, data, len);
231  }
232  log_compress2("COMPRESS: STATS: alone=%d compression-expand=%d "
233  "compression (before/after) = %d/%d",
236  log_compress2("COMPRESS: STATS: alone=%d compression-expand=%d "
237  "compression (before/after) = %d/%d",
240 
241 #if PACKET_SIZE_STATISTICS
242  {
243  static struct {
244  int counter;
245  int size;
246  } packets_stats[PACKET_LAST];
247  static int packet_counter = 0;
248  static int last_start_turn_seen = -1;
249  static bool start_turn_seen = FALSE;
250 
251  int size = len;
252  bool print = FALSE;
253  bool clear = FALSE;
254 
255  if (!packet_counter) {
256  int i;
257 
258  for (i = 0; i < PACKET_LAST; i++) {
259  packets_stats[i].counter = 0;
260  packets_stats[i].size = 0;
261  }
262  }
263 
264  packets_stats[packet_type].counter++;
265  packets_stats[packet_type].size += size;
266 
267  packet_counter++;
268  if (packet_type == PACKET_BEGIN_TURN
269  && last_start_turn_seen != game.info.turn) {
270  start_turn_seen = TRUE;
271  last_start_turn_seen = game.info.turn;
272  }
273 
274  if ((packet_type == PACKET_PROCESSING_FINISHED
275  || packet_type == PACKET_THAW_CLIENT)
276  && start_turn_seen) {
277  start_turn_seen = FALSE;
278  print = TRUE;
279  clear = TRUE;
280  }
281 
282  if (print) {
283  int i, sum = 0;
284 
285 #if PACKET_SIZE_STATISTICS == 2
286  delta_stats_report();
287 #endif
288  printf("Transmitted packets:\n");
289  printf("%8s %8s %8s %s", "Packets", "Bytes", "Byt/Pac", "Name\n");
290 
291  for (i = 0; i < PACKET_LAST; i++) {
292  if (packets_stats[i].counter == 0) {
293  continue;
294  }
295  sum += packets_stats[i].size;
296  printf("%8d %8d %8d %s(%i)\n", packets_stats[i].counter,
297  packets_stats[i].size,
298  packets_stats[i].size / packets_stats[i].counter,
299  packet_name(static_cast<enum packet_type>(i)), i);
300  }
301  printf("turn=%d; transmitted %d bytes in %d packets;average size "
302  "per packet %d bytes\n",
303  game.info.turn, sum, packet_counter, sum / packet_counter);
304  printf("turn=%d; transmitted %d bytes\n", game.info.turn,
305  pc->statistics.bytes_send);
306  }
307  if (clear) {
308  int i;
309 
310  for (i = 0; i < PACKET_LAST; i++) {
311  packets_stats[i].counter = 0;
312  packets_stats[i].size = 0;
313  }
314  packet_counter = 0;
315  pc->statistics.bytes_send = 0;
316  delta_stats_reset();
317  }
318  }
319 #endif // PACKET_SIZE_STATISTICS
320 
321  return result;
322 }
323 
330  enum packet_type *ptype)
331 {
332  int len_read;
333  int whole_packet_len;
334  struct {
335  enum packet_type type;
336  int itype;
337  } utype;
338  struct data_in din;
339  bool compressed_packet = false;
340  int header_size = 0;
341  void *data;
342  void *(*receive_handler)(struct connection *);
343 
344  if (!pc->used) {
345  return nullptr; // connection was closed, stop reading
346  }
347 
348  if (pc->buffer->ndata
350  // Not got enough for a length field yet
351  return nullptr;
352  }
353 
354  dio_input_init(&din, pc->buffer->data, pc->buffer->ndata);
355  dio_get_type_raw(&din, data_type(pc->packet_header.length), &len_read);
356 
357  // The non-compressed case
358  whole_packet_len = len_read;
359 
360  /* Compression signalling currently assumes a 2-byte packet length; if that
361  * changes, the protocol should probably be changed */
363  if (len_read == JUMBO_SIZE) {
364  compressed_packet = true;
365  header_size = 6;
366  if (dio_input_remaining(&din) >= 4) {
367  dio_get_uint32_raw(&din, &whole_packet_len);
368  log_compress("COMPRESS: got a jumbo packet of size %d",
369  whole_packet_len);
370  } else {
371  // to return nullptr below
372  whole_packet_len = 6;
373  }
374  } else if (len_read >= COMPRESSION_BORDER) {
375  compressed_packet = true;
376  header_size = 2;
377  whole_packet_len = len_read - COMPRESSION_BORDER;
378  log_compress("COMPRESS: got a normal packet of size %d",
379  whole_packet_len);
380  }
381 
382  if (static_cast<unsigned>(whole_packet_len) > pc->buffer->ndata) {
383  return nullptr; // not all data has been read
384  }
385 
386  if (whole_packet_len < header_size) {
387  qDebug("The packet size is reported to be less than header alone. "
388  "The connection will be closed now.");
389  connection_close(pc, _("illegal packet size"));
390 
391  return nullptr;
392  }
393 
394  if (compressed_packet) {
395  uLong compressed_size = whole_packet_len - header_size;
396  int decompress_factor = 80;
397  unsigned long int decompressed_size =
398  decompress_factor * compressed_size;
399  int error = Z_DATA_ERROR;
400  struct socket_packet_buffer *buffer = pc->buffer;
401  void *decompressed = fc_malloc(decompressed_size);
402 
403  do {
404  error =
405  uncompress(static_cast<Bytef *>(decompressed), &decompressed_size,
406  static_cast<const Bytef *>(
407  ADD_TO_POINTER(buffer->data, header_size)),
408  compressed_size);
409 
410  if (error == Z_DATA_ERROR) {
411  decompress_factor += 50;
412  decompressed_size = decompress_factor * compressed_size;
413  decompressed = fc_realloc(decompressed, decompressed_size);
414  }
415 
416  if (error != Z_OK) {
417  if (error != Z_DATA_ERROR || decompress_factor > MAX_DECOMPRESSION) {
418  qDebug("Uncompressing of the packet stream failed. "
419  "The connection will be closed now.");
420  connection_close(pc, _("decoding error"));
421  free(decompressed);
422  return nullptr;
423  }
424  }
425  } while (error != Z_OK);
426 
427  buffer->ndata -= whole_packet_len;
428  /*
429  * Remove the packet with the compressed data and shift all the
430  * remaining data to the front.
431  */
432  memmove(buffer->data, buffer->data + whole_packet_len, buffer->ndata);
433 
434  if (buffer->ndata + decompressed_size > buffer->nsize) {
435  buffer->nsize += decompressed_size;
436  buffer->data = static_cast<unsigned char *>(
437  fc_realloc(buffer->data, buffer->nsize));
438  }
439 
440  /*
441  * Make place for the uncompressed data by moving the remaining
442  * data.
443  */
444  memmove(buffer->data + decompressed_size, buffer->data, buffer->ndata);
445 
446  /*
447  * Copy the uncompressed data.
448  */
449  memcpy(buffer->data, decompressed, decompressed_size);
450 
451  free(decompressed);
452 
453  buffer->ndata += decompressed_size;
454 
455  log_compress("COMPRESS: decompressed %ld into %ld", compressed_size,
456  decompressed_size);
457 
458  return get_packet_from_connection(pc, ptype);
459  }
460 
461  /*
462  * At this point the packet is a plain uncompressed one. These have
463  * to have to be at least the header bytes in size.
464  */
465  if (whole_packet_len
468  qDebug("The packet stream is corrupt. The connection "
469  "will be closed now.");
470  connection_close(pc, _("decoding error"));
471  return nullptr;
472  }
473 
474  dio_get_type_raw(&din, data_type(pc->packet_header.type), &utype.itype);
475  utype.type = packet_type(utype.itype);
476 
477  if (utype.type >= PACKET_LAST
478  || (receive_handler = pc->phs.handlers->receive[utype.type])
479  == nullptr) {
480  qDebug("Received unsupported packet type %d (%s). The connection "
481  "will be closed now.",
482  utype.type, packet_name(utype.type));
483  connection_close(pc, _("unsupported packet type"));
484  return nullptr;
485  }
486 
487  log_packet("got packet type=(%s)%d len=%d from %s",
488  packet_name(utype.type), utype.itype, whole_packet_len,
489  is_server() ? pc->username : "server");
490 
491  *ptype = utype.type;
492 
493  if (pc->incoming_packet_notify) {
494  pc->incoming_packet_notify(pc, utype.type, whole_packet_len);
495  }
496 
497 #if PACKET_SIZE_STATISTICS
498  {
499  static struct {
500  int counter;
501  int size;
502  } packets_stats[PACKET_LAST];
503  static int packet_counter = 0;
504 
505  int packet_type = utype.itype;
506  int size = whole_packet_len;
507 
508  if (!packet_counter) {
509  int i;
510 
511  for (i = 0; i < PACKET_LAST; i++) {
512  packets_stats[i].counter = 0;
513  packets_stats[i].size = 0;
514  }
515  }
516 
517  packets_stats[packet_type].counter++;
518  packets_stats[packet_type].size += size;
519 
520  packet_counter++;
521  if (packet_counter % 100 == 0) {
522  int i, sum = 0;
523 
524  printf("Received packets:\n");
525  for (i = 0; i < PACKET_LAST; i++) {
526  if (packets_stats[i].counter == 0)
527  continue;
528  sum += packets_stats[i].size;
529  printf(" [%-25.25s %3d]: %6d packets; %8d bytes total; "
530  "%5d bytes/packet average\n",
531  packet_name(static_cast<enum packet_type>(i)), i,
532  packets_stats[i].counter, packets_stats[i].size,
533  packets_stats[i].size / packets_stats[i].counter);
534  }
535  printf("received %d bytes in %d packets;average size "
536  "per packet %d bytes\n",
537  sum, packet_counter, sum / packet_counter);
538  }
539  }
540 #endif // PACKET_SIZE_STATISTICS
541  data = receive_handler(pc);
542  if (!data) {
543  connection_close(pc, _("incompatible packet contents"));
544  return nullptr;
545  } else {
546  return data;
547  }
548 }
549 
554 {
555  struct data_in din;
556  int len;
557 
558  dio_input_init(&din, buffer->data, buffer->ndata);
560  memmove(buffer->data, buffer->data + len, buffer->ndata - len);
561  buffer->ndata -= len;
562  log_debug("remove_packet_from_buffer: remove %d; remaining %lu", len,
563  buffer->ndata);
564 }
565 
573 {
576 }
577 
582 static inline void packet_header_set(struct packet_header *packet_header)
583 {
584  // Ensure we have values initialized in packet_header_init().
587 
590 }
591 
596  struct connection *pconn, const struct packet_server_join_reply *packet)
597 {
598  if (packet->you_can_join) {
600  }
601 }
602 
607  struct connection *pconn, const struct packet_server_join_reply *packet)
608 {
609  if (packet->you_can_join) {
611  }
612 }
613 
617 bool packet_check(struct data_in *din, struct connection *pc)
618 {
619  size_t rem = dio_input_remaining(din);
620 
621  if (rem > 0) {
622  int type, len;
623 
624  dio_input_rewind(din);
626  dio_get_type_raw(din, data_type(pc->packet_header.type), &type);
627 
628  log_packet("received long packet (type %d, len %d, rem %lu) from %s",
629  type, len, static_cast<unsigned long>(rem),
630  conn_description(pc));
631  return false;
632  }
633  return true;
634 }
635 
640  struct player *pplayer,
641  const struct packet_player_attribute_chunk *chunk)
642 {
643  log_packet("received attribute chunk %u/%u %u",
644  static_cast<unsigned int>(chunk->offset),
645  static_cast<unsigned int>(chunk->total_length),
646  static_cast<unsigned int>(chunk->chunk_length));
647 
648  fc_assert_ret(chunk->chunk_length < ATTRIBUTE_CHUNK_SIZE);
649 
650  if (chunk->total_length < 0 || chunk->chunk_length < 0
651  || chunk->total_length >= MAX_ATTRIBUTE_BLOCK || chunk->offset < 0
652  || chunk->offset
653  > chunk->total_length // necessary check on 32 bit systems
654  || chunk->chunk_length > chunk->total_length
655  || chunk->offset + chunk->chunk_length > chunk->total_length
656  || (chunk->offset != 0
657  && chunk->total_length
658  != pplayer->attribute_block_buffer.size())) {
659  // wrong attribute data
660  pplayer->attribute_block_buffer.clear();
661  qCritical("Received wrong attribute chunk");
662  return;
663  }
664  // first one in a row
665  if (chunk->offset == 0) {
666  pplayer->attribute_block_buffer.resize(chunk->total_length);
667  }
668  memcpy(pplayer->attribute_block_buffer.data() + chunk->offset, chunk->data,
669  chunk->chunk_length);
670 
671  if (chunk->offset + chunk->chunk_length == chunk->total_length) {
672  // Received full attribute block
673  pplayer->attribute_block = pplayer->attribute_block_buffer;
674  pplayer->attribute_block_buffer.clear();
675  }
676 }
677 
681 void send_attribute_block(const struct player *pplayer,
682  struct connection *pconn)
683 {
684  struct packet_player_attribute_chunk packet;
685 
686  if (!pplayer || pplayer->attribute_block.isEmpty()) {
687  return;
688  }
689 
691 
692  auto chunks =
693  (pplayer->attribute_block.size() - 1) / ATTRIBUTE_CHUNK_SIZE + 1;
694  auto bytes_left = pplayer->attribute_block.size();
695 
696  connection_do_buffer(pconn);
697 
698  for (int current_chunk = 0; current_chunk < chunks; current_chunk++) {
699  int size_of_current_chunk = MIN(bytes_left, ATTRIBUTE_CHUNK_SIZE - 1);
700 
701  packet.offset = (ATTRIBUTE_CHUNK_SIZE - 1) * current_chunk;
702  packet.total_length = pplayer->attribute_block.size();
703  packet.chunk_length = size_of_current_chunk;
704 
705  memcpy(packet.data, pplayer->attribute_block.data() + packet.offset,
706  packet.chunk_length);
707  bytes_left -= packet.chunk_length;
708 
709  if (packet.chunk_length < ATTRIBUTE_CHUNK_SIZE - 1) {
710  /* Last chunk is not full. Make sure that delta does
711  * not use random data. */
712  memset(packet.data + packet.chunk_length, 0,
713  ATTRIBUTE_CHUNK_SIZE - 1 - packet.chunk_length);
714  }
715 
716  send_packet_player_attribute_chunk(pconn, &packet);
717  }
718 
719  connection_do_unbuffer(pconn);
720 }
721 
726  struct connection *pc, struct packet_player_attribute_chunk *packet)
727 {
728  Q_UNUSED(pc)
729  fc_assert(packet->total_length > 0
730  && packet->total_length < MAX_ATTRIBUTE_BLOCK);
731  // 500 bytes header, just to be sure
732  fc_assert(packet->chunk_length > 0
733  && packet->chunk_length < MAX_LEN_PACKET - 500);
734  fc_assert(packet->chunk_length <= packet->total_length);
735  fc_assert(packet->offset >= 0 && packet->offset < packet->total_length);
736 
737  log_packet("sending attribute chunk %d/%d %d", packet->offset,
738  packet->total_length, packet->chunk_length);
739 }
740 
744 static void packet_handlers_free() {}
745 
750 {
751  static struct packet_handlers default_handlers;
752  static bool initialized = false;
753 
754  if (!initialized) {
755  memset(&default_handlers, 0, sizeof(default_handlers));
756  packet_handlers_fill_initial(&default_handlers);
757  initialized = true;
758  }
759 
760  return &default_handlers;
761 }
762 
766 const struct packet_handlers *packet_handlers_get(const char *capability)
767 {
768  struct packet_handlers *phandlers;
769  char functional_capability[MAX_LEN_CAPSTR] = "";
770  QStringList tokens;
771 
772  fc_assert(strlen(capability) < sizeof(functional_capability));
773 
774  // Get functional network capability string.
775  tokens = QString(capability).split(QRegularExpression("[ \t\n,]+"));
776  tokens.sort();
777 
778  for (const auto &str : qAsConst(tokens)) {
779  if (!has_capability(qUtf8Printable(str), packet_functional_capability)) {
780  continue;
781  }
782  if (functional_capability[0] != '\0') {
783  sz_strlcat(functional_capability, " ");
784  }
785  sz_strlcat(functional_capability, qUtf8Printable(str));
786  }
787 
788  // Lookup handlers for the capabilities or create new handlers.
789  if (!packet_handlers_hash->contains(functional_capability)) {
790  phandlers = new struct packet_handlers;
791  memcpy(phandlers, packet_handlers_initial(), sizeof(*phandlers));
792  packet_handlers_fill_capability(phandlers, functional_capability);
793  packet_handlers_hash->insert(functional_capability, phandlers);
794  }
795  phandlers = packet_handlers_hash->value(functional_capability);
796  fc_assert(phandlers != nullptr);
797  return phandlers;
798 }
799 
805 
807  QVector<QString> *qstrvec)
808 {
809  if (qstrvec == nullptr) {
810  str[0] = '\0';
811  return;
812  }
813 
814  const auto joined =
815  QStringList::fromVector(*qstrvec).join(PACKET_STRVEC_SEPARATOR);
816  qstrncpy(str, qUtf8Printable(joined), MAX_LEN_PACKET);
817 }
818 
820 {
821  QVector<QString> *qstrvec = nullptr;
822  if ('\0' != str[0]) {
823  qstrvec = new QVector<QString>;
825  }
826  return qstrvec;
827 }
828 
838 void qstrvec_from_str(QVector<QString> *psv, char separator, const char *str)
839 {
840  const char *p;
841  char *new_str;
842 
843  psv->clear();
844  while ((p = strchr(str, separator))) {
845  new_str = new char[p - str + 1];
846  memcpy(new_str, str, p - str);
847  new_str[p - str] = '\0';
848  psv->append(new_str);
849  str = p + 1;
850  delete[] new_str;
851  }
852  if ('\0' != *str) {
853  psv->append(str);
854  }
855 }
bool has_capability(const char *cap, const char *capstr)
Wrapper for fc_has_capability() for nullptr terminated strings.
Definition: capability.cpp:71
int get_next_request_id(int old_request_id)
Get next request id.
Definition: connection.cpp:490
const char * conn_description(const struct connection *pconn, bool is_private)
° Return pointer to static string containing a description for this ° connection, based on pconn->nam...
Definition: connection.cpp:431
void connection_do_buffer(struct connection *pc)
Turn on buffering, using a counter so that calls may be nested.
Definition: connection.cpp:278
void connection_close(struct connection *pconn, const QString &reason)
Call the conn_close_callback.
Definition: connection.cpp:69
bool connection_send_data(struct connection *pconn, const unsigned char *data, int len)
Write data to socket.
Definition: connection.cpp:245
bool conn_compression_frozen(const struct connection *pconn)
Returns TRUE if the connection is frozen.
Definition: connection.cpp:648
void connection_do_unbuffer(struct connection *pc)
Turn off buffering if internal counter of number of times buffering was turned on falls to zero,...
Definition: connection.cpp:290
#define MAX_LEN_PACKET
Definition: connection.h:41
#define MAX_LEN_BUFFER
Definition: connection.h:47
#define MAX_LEN_CAPSTR
Definition: connection.h:42
void dio_output_init(struct raw_data_out *dout, void *destination, size_t dest_size)
Initializes the output to the given output buffer and the given buffer size.
Definition: dataio_raw.cpp:144
void dio_put_uint16_raw(struct raw_data_out *dout, int value)
Insert value using 16 bits.
Definition: dataio_raw.cpp:248
size_t dio_input_remaining(struct data_in *din)
Return the number of unread bytes.
Definition: dataio_raw.cpp:185
bool dio_get_uint32_raw(struct data_in *din, int *dest)
Receive uint32 value to dest.
Definition: dataio_raw.cpp:534
void dio_input_rewind(struct data_in *din)
Rewinds the stream so that the get-functions start from the beginning.
Definition: dataio_raw.cpp:180
void dio_put_uint32_raw(struct raw_data_out *dout, int value)
Insert value using 32 bits.
Definition: dataio_raw.cpp:267
bool dio_get_uint16_raw(struct data_in *din, int *dest)
Receive uint16 value to dest.
Definition: dataio_raw.cpp:513
bool dio_get_type_raw(struct data_in *din, enum data_type type, int *dest)
Receive value using 'size' bits to dest.
Definition: dataio_raw.cpp:555
size_t data_type_size(enum data_type type)
Return the size of the data_type in bytes.
Definition: dataio_raw.cpp:193
void dio_input_init(struct data_in *din, const void *src, size_t src_size)
Initializes the input to the given input buffer and the given number of valid input bytes.
Definition: dataio_raw.cpp:169
data_type
Definition: dataio_raw.h:37
@ DIOT_UINT8
Definition: dataio_raw.h:38
@ DIOT_UINT16
Definition: dataio_raw.h:39
static bool initialized
Definition: effects.cpp:32
#define _(String)
Definition: fcintl.h:50
struct civ_game game
Definition: game.cpp:47
bool is_server()
Is program type server?
Definition: game.cpp:57
#define fc_assert_ret(condition)
Definition: log.h:112
#define log_packet
Definition: log.h:72
#define fc_assert(condition)
Definition: log.h:89
#define fc_assert_action_msg(condition, action, message,...)
Definition: log.h:121
#define fc_assert_ret_val(condition, val)
Definition: log.h:114
#define log_debug(message,...)
Definition: log.h:65
#define FC_STATIC_ASSERT(cond, tag)
Definition: log.h:158
#define log_compress2
Definition: packets.cpp:47
void post_receive_packet_server_join_reply(struct connection *pconn, const struct packet_server_join_reply *packet)
Modify if needed the packet header field lengths.
Definition: packets.cpp:606
#define COMPRESSION_BORDER
Definition: packets.cpp:39
void packets_deinit()
Call when there is no longer a requirement for protocol processing.
Definition: packets.cpp:804
static int get_compression_level()
Returns the compression level.
Definition: packets.cpp:70
void packet_strvec_compute(char str[MAX_LEN_PACKET], QVector< QString > *qstrvec)
Definition: packets.cpp:806
const struct packet_handlers * packet_handlers_get(const char *capability)
Returns the packet handlers variant for 'capability'.
Definition: packets.cpp:766
#define MAX_DECOMPRESSION
Definition: packets.cpp:49
bool packet_check(struct data_in *din, struct connection *pc)
Sanity check packet.
Definition: packets.cpp:617
void packet_header_init(struct packet_header *packet_header)
Set the packet header field lengths used for the login protocol, before the capability of the connect...
Definition: packets.cpp:572
void * get_packet_from_connection_raw(struct connection *pc, enum packet_type *ptype)
Read and return a packet from the connection 'pc'.
Definition: packets.cpp:329
bool conn_compression_thaw(struct connection *pconn)
Thaw the connection.
Definition: packets.cpp:160
const struct packet_handlers * packet_handlers_initial()
Returns the packet handlers variant with no special capability.
Definition: packets.cpp:749
const char *const packet_functional_capability
Definition: packets.cpp:57
void qstrvec_from_str(QVector< QString > *psv, char separator, const char *str)
Build the string vector from a string until 'str_size' bytes are read.
Definition: packets.cpp:838
void pre_send_packet_player_attribute_chunk(struct connection *pc, struct packet_player_attribute_chunk *packet)
Test and log for sending player attribute_block.
Definition: packets.cpp:725
#define JUMBO_BORDER
Definition: packets.cpp:44
static void packet_header_set(struct packet_header *packet_header)
Set the packet header field lengths used after the login protocol, after the capability of the connec...
Definition: packets.cpp:582
static int stat_size_compressed
Definition: packets.cpp:64
void remove_packet_from_buffer(struct socket_packet_buffer *buffer)
Remove the packet from the buffer.
Definition: packets.cpp:553
void post_send_packet_server_join_reply(struct connection *pconn, const struct packet_server_join_reply *packet)
Modify if needed the packet header field lengths.
Definition: packets.cpp:595
static void packet_handlers_free()
Destroy the packet handler hash table.
Definition: packets.cpp:744
#define JUMBO_SIZE
Definition: packets.cpp:34
static int stat_size_uncompressed
Definition: packets.cpp:63
int send_packet_data(struct connection *pc, unsigned char *data, int len, enum packet_type packet_type)
It returns the request id of the outgoing packet (or 0 if is_server()).
Definition: packets.cpp:176
#define MAX_LEN_COMPRESS_QUEUE
QHash< QString, struct packet_handlers * > packetsHash
Definition: packets.cpp:59
QVector< QString > * packet_strvec_extract(const char *str)
Definition: packets.cpp:819
static int stat_size_alone
Definition: packets.cpp:62
void generic_handle_player_attribute_chunk(struct player *pplayer, const struct packet_player_attribute_chunk *chunk)
Updates pplayer->attribute_block according to the given packet.
Definition: packets.cpp:639
static int stat_size_no_compression
Definition: packets.cpp:65
void send_attribute_block(const struct player *pplayer, struct connection *pconn)
Split the attribute block into chunks and send them over pconn.
Definition: packets.cpp:681
static bool conn_compression_flush(struct connection *pconn)
Send all waiting data.
Definition: packets.cpp:88
#define PACKET_STRVEC_SEPARATOR
Definition: packets.cpp:40
#define log_compress
Definition: packets.cpp:46
#define ATTRIBUTE_CHUNK_SIZE
Definition: packets.h:49
#define get_packet_from_connection(pc, ptype)
Definition: packets.h:90
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)
int len
Definition: packhand.cpp:127
#define MAX_ATTRIBUTE_BLOCK
Definition: player.h:219
Q_GLOBAL_STATIC(QVector< QString >, future_name_translation)
struct setting_list * level[OLEVELS_NUM]
Definition: settings.cpp:167
bool str_to_int(const char *str, int *pint)
Convert 'str' to it's int reprentation if possible.
Definition: shared.cpp:384
#define ADD_TO_POINTER(p, n)
Definition: shared.h:80
#define MIN(x, y)
Definition: shared.h:49
size_t size
Definition: specvec.h:64
struct packet_game_info info
Definition: game.h:80
const struct packet_handlers * handlers
Definition: connection.h:247
struct connection::@58 compression
struct connection::@59 statistics
struct connection::@57 phs
struct packet_header packet_header
Definition: connection.h:132
char username[MAX_LEN_NAME]
Definition: connection.h:151
void(* incoming_packet_notify)(struct connection *pc, int packet_type, int size)
Definition: connection.h:234
int bytes_send
Definition: connection.h:256
void(* outgoing_packet_notify)(struct connection *pc, int packet_type, int size, int request_id)
Definition: connection.h:242
struct connection::@55::@60 client
struct byte_vector queue
Definition: connection.h:253
int frozen_level
Definition: connection.h:251
struct socket_packet_buffer * buffer
Definition: connection.h:144
void *(* receive[PACKET_LAST])(struct connection *pconn)
Definition: packets.h:84
unsigned int length
Definition: connection.h:115
unsigned int type
Definition: connection.h:116
Definition: player.h:231
QByteArray attribute_block
Definition: player.h:288
QByteArray attribute_block_buffer
Definition: player.h:289
unsigned long ndata
Definition: connection.h:108
unsigned long nsize
Definition: connection.h:110
unsigned char * data
Definition: connection.h:111
#define fc_realloc(ptr, sz)
Definition: support.h:59
#define fc_malloc(sz)
Definition: support.h:58
#define sz_strlcat(dest, src)
Definition: support.h:142