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

Freeciv-3.1

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 set generate_stats
54 * to 1 in generate_packets.py.
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/**********************************************************************/
71void *get_packet_from_connection_json(struct connection *pc,
72 enum packet_type *ptype)
73{
74 int len_read;
75 int whole_packet_len;
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 got enough for a length field yet */
92 return NULL;
93 }
94
95 dio_input_init(&din, pc->buffer->data, pc->buffer->ndata);
96 dio_get_uint16_raw(&din, &len_read);
97
98 /* The non-compressed case */
99 whole_packet_len = len_read;
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 return NULL;
114 }
115
116 /*
117 * The server tries to parse as JSON the first packet that it gets on a
118 * connection. If it is a valid JSON packet, the connection is switched
119 * to JSON mode.
120 */
121 if (is_server() && pc->server.last_request_id_seen == 0) {
122 /* Try to parse JSON packet. Note that json string has '\0' */
123 pc->json_packet = json_loadb((char*)pc->buffer->data + 2, whole_packet_len - 3, 0, &error);
124
125 /* Set the connection mode */
126 pc->json_mode = (pc->json_packet != NULL);
127 }
128
129 if (pc->json_mode) {
130 /* Parse JSON packet. Note that json string has '\0' */
131 pc->json_packet = json_loadb((char*)pc->buffer->data + 2, whole_packet_len - 3, 0, &error);
132
133 /* Log errors before we scrap the data */
134 if (!pc->json_packet) {
135 log_error("ERROR: Unable to parse packet: %s", pc->buffer->data + 2);
136 log_error("%s", error.text);
137 }
138
139 log_packet_json("Json in: %s", pc->buffer->data + 2);
140
141 /* Shift remaining data to the front */
142 pc->buffer->ndata -= whole_packet_len;
143 memmove(pc->buffer->data, pc->buffer->data + whole_packet_len, pc->buffer->ndata);
144
145 if (!pc->json_packet) {
146 return NULL;
147 }
148
149 pint = json_object_get(pc->json_packet, "pid");
150
151 if (!pint) {
152 log_error("ERROR: Unable to get packet type.");
153 return NULL;
154 }
155
156 json_int_t packet_type = json_integer_value(pint);
157 utype.type = packet_type;
158 } else {
159 dio_get_type_raw(&din, pc->packet_header.type, &utype.itype);
160 utype.type = utype.itype;
161 }
162
163 if (utype.type >= PACKET_LAST
164 || (receive_handler = pc->phs.handlers->receive[utype.type]) == NULL) {
165 log_verbose("Received unsupported packet type %d (%s). The connection "
166 "will be closed now.",
167 utype.type, packet_name(utype.type));
168 connection_close(pc, _("unsupported packet type"));
169 return NULL;
170 }
171
172 log_packet("got packet type=(%s) len=%d from %s",
173 packet_name(utype.type), whole_packet_len,
174 is_server() ? pc->username : "server");
175
176 *ptype = utype.type;
177
178 if (pc->incoming_packet_notify) {
179 pc->incoming_packet_notify(pc, utype.type, whole_packet_len);
180 }
181
182#if PACKET_SIZE_STATISTICS
183 {
184 static struct {
185 int counter;
186 int size;
187 } packets_stats[PACKET_LAST];
188 static int packet_counter = 0;
189
190 int packet_type = utype.itype;
191 int size = whole_packet_len;
192
193 if (!packet_counter) {
194 int i;
195
196 for (i = 0; i < PACKET_LAST; i++) {
197 packets_stats[i].counter = 0;
198 packets_stats[i].size = 0;
199 }
200 }
201
202 packets_stats[packet_type].counter++;
203 packets_stats[packet_type].size += size;
204
205 packet_counter++;
206 if (packet_counter % 100 == 0) {
207 int i, sum = 0;
208
209 log_test("Received packets:");
210 for (i = 0; i < PACKET_LAST; i++) {
211 if (packets_stats[i].counter == 0)
212 continue;
213 sum += packets_stats[i].size;
214 log_test(" [%-25.25s %3d]: %6d packets; %8d bytes total; "
215 "%5d bytes/packet average",
216 packet_name(i), i, packets_stats[i].counter,
217 packets_stats[i].size,
218 packets_stats[i].size / packets_stats[i].counter);
219 }
220 log_test("received %d bytes in %d packets;average size "
221 "per packet %d bytes",
222 sum, packet_counter, sum / packet_counter);
223 }
224 }
225#endif /* PACKET_SIZE_STATISTICS */
226 data = receive_handler(pc);
227 if (!data) {
228 connection_close(pc, _("incompatible packet contents"));
229 return NULL;
230 } else {
231 return data;
232 }
233}
234
235#endif /* FREECIV_JSON_CONNECTION */
capability.h
connection_close
void connection_close(struct connection *pconn, const char *reason)
Definition connection.c:88
dataio.h
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
events.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.h
type
GType type
Definition repodlgs.c:1312
log.h
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
log_error
#define log_error(message,...)
Definition log.h:103
map.h
mem.h
packet_functional_capability
const char *const packet_functional_capability
Definition packets_gen.c:32
packet_name
const char * packet_name(enum packet_type type)
Definition packets_gen.c:49
packet_type
packet_type
Definition packets_gen.h:1883
PACKET_LAST
@ PACKET_LAST
Definition packets_gen.h:2078
packets_json.h
log_packet_json
#define log_packet_json
Definition packets_json.h:22
get_packet_from_connection_json
void * get_packet_from_connection_json(struct connection *pc, enum packet_type *ptype)
shared.h
spechash.h
size
size_t size
Definition specvec.h:72
connection
Definition connection.h:141
connection::handlers
const struct packet_handlers * handlers
Definition connection.h:267
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::server
struct connection::@57::@63 server
connection::incoming_packet_notify
void(* incoming_packet_notify)(struct connection *pc, int packet_type, int size)
Definition connection.h:253
connection::buffer
struct socket_packet_buffer * buffer
Definition connection.h:158
connection::last_request_id_seen
int last_request_id_seen
Definition connection.h:206
connection::used
bool used
Definition connection.h:144
data_in
Definition dataio_raw.h:30
packet_handlers::receive
void *(* receive[PACKET_LAST])(struct connection *pconn)
Definition packets.h:104
packet_header::length
unsigned int length
Definition connection.h:129
packet_header::type
unsigned int type
Definition connection.h:130
socket_packet_buffer::ndata
int ndata
Definition connection.h:122
socket_packet_buffer::data
unsigned char * data
Definition connection.h:125
support.h