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)
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 ***********************************************************************/
15 #include <fc_config.h>
18 #ifdef FREECIV_JSON_CONNECTION
20 #include "fc_prehdrs.h"
27 #ifdef HAVE_ARPA_INET_H
28 #include <arpa/inet.h>
30 #ifdef HAVE_NETINET_IN_H
31 #include <netinet/in.h>
37 #include "capability.h"
50 #include "packets_json.h"
53 * Valid values are 0, 1 and 2. For 2 you have to set generate_stats
54 * to 1 in generate_packets.py.
56 #define PACKET_SIZE_STATISTICS 0
58 extern const char *const packet_functional_capability
;
60 #define SPECHASH_TAG packet_handler
61 #define SPECHASH_ASTR_KEY_TYPE
62 #define SPECHASH_IDATA_TYPE struct packet_handlers *
63 #define SPECHASH_IDATA_FREE (packet_handler_hash_data_free_fn_t) free
66 /**************************************************************************
67 Read and return a packet from the connection 'pc'. The type of the
68 packet is written in 'ptype'. On error, the connection is closed and
69 the function returns NULL.
70 **************************************************************************/
71 void *get_packet_from_connection_json(struct connection
*pc
,
72 enum packet_type
*ptype
)
77 enum packet_type type
;
82 void *(*receive_handler
)(struct connection
*);
87 return NULL
; /* connection was closed, stop reading */
90 if (pc
->buffer
->ndata
< data_type_size(pc
->packet_header
.length
)) {
91 /* Not got enough for a length field yet */
95 dio_input_init(&din
, pc
->buffer
->data
, pc
->buffer
->ndata
);
96 dio_get_uint16_raw(&din
, &len_read
);
98 /* The non-compressed case */
99 whole_packet_len
= len_read
;
101 if ((unsigned)whole_packet_len
> pc
->buffer
->ndata
) {
102 return NULL
; /* not all data has been read */
106 * At this point the packet is a plain uncompressed one. These have
107 * to have to be at least the header bytes in size.
109 if (whole_packet_len
< (data_type_size(pc
->packet_header
.length
))) {
110 log_verbose("The packet stream is corrupt. The connection "
111 "will be closed now.");
112 connection_close(pc
, _("decoding error"));
116 /* Parse JSON packet. Note that json string has '\0' */
117 pc
->json_packet
= json_loadb((char*)pc
->buffer
->data
+ 2, whole_packet_len
- 3, 0, &error
);
119 /* Log errors before we scrap the data */
120 if (!pc
->json_packet
) {
121 log_error("ERROR: Unable to parse packet: %s", pc
->buffer
->data
+ 2);
122 log_error("%s", error
.text
);
125 log_packet_json("Json in: %s", pc
->buffer
->data
+ 2);
127 /* Shift remaining data to the front */
128 pc
->buffer
->ndata
-= whole_packet_len
;
129 memmove(pc
->buffer
->data
, pc
->buffer
->data
+ whole_packet_len
, pc
->buffer
->ndata
);
131 if (!pc
->json_packet
) {
135 pint
= json_object_get(pc
->json_packet
, "pid");
138 log_error("ERROR: Unable to get packet type.");
142 json_int_t packet_type
= json_integer_value(pint
);
143 utype
.type
= packet_type
;
146 || utype
.type
>= PACKET_LAST
147 || (receive_handler
= pc
->phs
.handlers
->receive
[utype
.type
]) == NULL
) {
148 log_verbose("Received unsupported packet type %d (%s). The connection "
149 "will be closed now.",
150 utype
.type
, packet_name(utype
.type
));
151 connection_close(pc
, _("unsupported packet type"));
155 log_packet("got packet type=(%s) len=%d from %s",
156 packet_name(utype
.type
), whole_packet_len
,
157 is_server() ? pc
->username
: "server");
161 if (pc
->incoming_packet_notify
) {
162 pc
->incoming_packet_notify(pc
, utype
.type
, whole_packet_len
);
165 #if PACKET_SIZE_STATISTICS
170 } packets_stats
[PACKET_LAST
];
171 static int packet_counter
= 0;
173 int packet_type
= utype
.itype
;
174 int size
= whole_packet_len
;
176 if (!packet_counter
) {
179 for (i
= 0; i
< PACKET_LAST
; i
++) {
180 packets_stats
[i
].counter
= 0;
181 packets_stats
[i
].size
= 0;
185 packets_stats
[packet_type
].counter
++;
186 packets_stats
[packet_type
].size
+= size
;
189 if (packet_counter
% 100 == 0) {
192 log_test("Received packets:");
193 for (i
= 0; i
< PACKET_LAST
; i
++) {
194 if (packets_stats
[i
].counter
== 0)
196 sum
+= packets_stats
[i
].size
;
197 log_test(" [%-25.25s %3d]: %6d packets; %8d bytes total; "
198 "%5d bytes/packet average",
199 packet_name(i
), i
, packets_stats
[i
].counter
,
200 packets_stats
[i
].size
,
201 packets_stats
[i
].size
/ packets_stats
[i
].counter
);
203 log_test("received %d bytes in %d packets;average size "
204 "per packet %d bytes",
205 sum
, packet_counter
, sum
/ packet_counter
);
208 #endif /* PACKET_SIZE_STATISTICS */
209 data
= receive_handler(pc
);
211 connection_close(pc
, _("incompatible packet contents"));
218 #endif /* FREECIV_JSON_CONNECTION */