Freeciv-3.3
Loading...
Searching...
No Matches
packets_json.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#ifdef FREECIV_JSON_CONNECTION
19
20#include "fc_prehdrs.h"
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <limits.h>
26
27#ifdef HAVE_ARPA_INET_H
28#include <arpa/inet.h>
29#endif
30#ifdef HAVE_NETINET_IN_H
31#include <netinet/in.h>
32#endif
33
34#include <jansson.h>
35
36/* utility */
37#include "capability.h"
38#include "fcintl.h"
39#include "log.h"
40#include "mem.h"
41#include "shared.h"
42#include "support.h"
43
44/* common */
45#include "dataio.h"
46#include "game.h"
47#include "events.h"
48#include "map.h"
49
50#include "packets_json.h"
51
52/*
53 * Valid values are 0, 1 and 2. For 2 you have to run generate_packets.py
54 * with --gen-stats.
55 */
56#define PACKET_SIZE_STATISTICS 0
57
58extern const char *const packet_functional_capability;
59
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
64#include "spechash.h"
65
66/**********************************************************************/
72 enum packet_type *ptype)
73{
74 int len_read;
76 struct {
77 enum packet_type type;
78 int itype;
79 } utype;
80 struct data_in din;
81 void *data;
82 void *(*receive_handler)(struct connection *);
83 json_error_t error;
84 json_t *pint;
85
86 if (!pc->used) {
87 return NULL; /* Connection was closed, stop reading */
88 }
89
90 if (pc->buffer->ndata < data_type_size(pc->packet_header.length)) {
91 /* Not enough for a length field yet */
92 return NULL;
93 }
94
95 dio_input_init(&din, pc->buffer->data, pc->buffer->ndata);
97
98 /* The non-compressed case */
100
101 if ((unsigned)whole_packet_len > pc->buffer->ndata) {
102 return NULL; /* Not all data has been read */
103 }
104
105 /*
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.
108 */
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"));
113
114 return NULL;
115 }
116
117 /*
118 * The server tries to parse as JSON the first packet that it gets on a
119 * connection. If it is a valid JSON packet, the connection is switched
120 * to JSON mode.
121 */
122 if (is_server() && pc->server.last_request_id_seen == 0) {
123 /* Try to parse JSON packet. Note that json string has '\0' */
124 pc->json_packet = json_loadb((char*)pc->buffer->data + 2,
125 whole_packet_len - 3, 0, &error);
126
127 /* Set the connection mode */
128 pc->json_mode = (pc->json_packet != NULL);
129 }
130
131 if (pc->json_mode) {
132 /* Parse JSON packet. Note that json string has '\0' */
133 pc->json_packet = json_loadb((char*)pc->buffer->data + 2,
134 whole_packet_len - 3, 0, &error);
135
136 /* Log errors before we scrap the data */
137 if (!pc->json_packet) {
138 log_error("ERROR: Unable to parse packet: %s", pc->buffer->data + 2);
139 log_error("%s", error.text);
140 }
141
142 log_packet_json("Json in: %s", pc->buffer->data + 2);
143
144 /* Shift remaining data to the front */
145 pc->buffer->ndata -= whole_packet_len;
146 memmove(pc->buffer->data, pc->buffer->data + whole_packet_len,
147 pc->buffer->ndata);
148
149 if (!pc->json_packet) {
150 return NULL;
151 }
152
153 pint = json_object_get(pc->json_packet, "pid");
154
155 if (!pint) {
156 log_error("ERROR: Unable to get packet type.");
157 return NULL;
158 }
159
160 utype.type = json_integer_value(pint);
161 } else {
162 dio_get_type_raw(&din, pc->packet_header.type, &utype.itype);
163 utype.type = utype.itype;
164 }
165
166 if (utype.type >= PACKET_LAST
167 || (receive_handler = pc->phs.handlers->receive[utype.type]) == NULL) {
168 log_verbose("Received unsupported packet type %d (%s). The connection "
169 "will be closed now.",
170 utype.type, packet_name(utype.type));
171 connection_close(pc, _("unsupported packet type"));
172
173 return NULL;
174 }
175
176 log_packet("got packet type=(%s) len=%d from %s",
177 packet_name(utype.type), whole_packet_len,
178 is_server() ? pc->username : "server");
179
180 *ptype = utype.type;
181
182 if (pc->incoming_packet_notify) {
183 pc->incoming_packet_notify(pc, utype.type, whole_packet_len);
184 }
185
186#if PACKET_SIZE_STATISTICS
187 {
188 static struct {
189 int counter;
190 int size;
192 static int packet_counter = 0;
193
194 int packet_type = utype.itype;
196
197 if (!packet_counter) {
198 int i;
199
200 for (i = 0; i < PACKET_LAST; i++) {
201 packets_stats[i].counter = 0;
202 packets_stats[i].size = 0;
203 }
204 }
205
206 packets_stats[packet_type].counter++;
208
210 if (packet_counter % 100 == 0) {
211 int i, sum = 0;
212
213 log_test("Received packets:");
214 for (i = 0; i < PACKET_LAST; i++) {
215 if (packets_stats[i].counter == 0) {
216 continue;
217 }
218 sum += packets_stats[i].size;
219 log_test(" [%-25.25s %3d]: %6d packets; %8d bytes total; "
220 "%5d bytes/packet average",
224 }
225
226 log_test("received %d bytes in %d packets;average size "
227 "per packet %d bytes",
228 sum, packet_counter, sum / packet_counter);
229 }
230 }
231#endif /* PACKET_SIZE_STATISTICS */
232
233 data = receive_handler(pc);
234 if (!data) {
235 connection_close(pc, _("incompatible packet contents"));
236 return NULL;
237 } else {
238 return data;
239 }
240}
241
242#endif /* FREECIV_JSON_CONNECTION */
char * incite_cost
Definition comments.c:76
void connection_close(struct connection *pconn, const char *reason)
Definition connection.c:88
bool dio_get_uint16_raw(struct data_in *din, int *dest)
Definition dataio_raw.c:619
bool dio_get_type_raw(struct data_in *din, enum data_type type, int *dest)
Definition dataio_raw.c:661
size_t data_type_size(enum data_type type)
Definition dataio_raw.c:229
void dio_input_init(struct data_in *din, const void *src, size_t src_size)
Definition dataio_raw.c:202
static bool is_server(void)
#define _(String)
Definition fcintl.h:67
GType type
Definition repodlgs.c:1313
#define log_packet
Definition log.h:138
#define log_test
Definition log.h:137
#define log_verbose(message,...)
Definition log.h:110
#define log_error(message,...)
Definition log.h:104
const char *const packet_functional_capability
Definition packets_gen.c:30
const char * packet_name(enum packet_type type)
Definition packets_gen.c:47
packet_type
@ PACKET_LAST
#define log_packet_json
void * get_packet_from_connection_json(struct connection *pc, enum packet_type *ptype)
size_t size
Definition specvec.h:72