aboutsummaryrefslogtreecommitdiff
path: root/src/lib/gnsrecord/json_gnsrecord.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/gnsrecord/json_gnsrecord.c')
-rw-r--r--src/lib/gnsrecord/json_gnsrecord.c389
1 files changed, 389 insertions, 0 deletions
diff --git a/src/lib/gnsrecord/json_gnsrecord.c b/src/lib/gnsrecord/json_gnsrecord.c
new file mode 100644
index 000000000..cc96e42fb
--- /dev/null
+++ b/src/lib/gnsrecord/json_gnsrecord.c
@@ -0,0 +1,389 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file json/json_gnsrecord.c
23 * @brief JSON handling of GNS record data
24 * @author Philippe Buschmann
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_json_lib.h"
29#include "gnunet_gnsrecord_lib.h"
30
31#define GNUNET_JSON_GNSRECORD_VALUE "value"
32#define GNUNET_JSON_GNSRECORD_RECORD_DATA "data"
33#define GNUNET_JSON_GNSRECORD_TYPE "record_type"
34#define GNUNET_JSON_GNSRECORD_RELATIVE_EXPIRATION_TIME "relative_expiration"
35#define GNUNET_JSON_GNSRECORD_ABSOLUTE_EXPIRATION_TIME "absolute_expiration"
36#define GNUNET_JSON_GNSRECORD_FLAG_PRIVATE "is_private"
37#define GNUNET_JSON_GNSRECORD_FLAG_SUPPLEMENTAL "is_supplemental"
38#define GNUNET_JSON_GNSRECORD_FLAG_RELATIVE "is_relative_expiration"
39#define GNUNET_JSON_GNSRECORD_FLAG_SHADOW "is_shadow"
40#define GNUNET_JSON_GNSRECORD_RECORD_NAME "record_name"
41
42struct GnsRecordInfo
43{
44 char **name;
45
46 unsigned int *rd_count;
47
48 struct GNUNET_GNSRECORD_Data **rd;
49};
50
51
52static void
53cleanup_recordinfo (struct GnsRecordInfo *gnsrecord_info)
54{
55 char *tmp;
56
57 if (NULL != *(gnsrecord_info->rd))
58 {
59 for (int i = 0; i < *(gnsrecord_info->rd_count); i++)
60 {
61 tmp = (char*) (*(gnsrecord_info->rd))[i].data;
62 if (NULL != tmp)
63 GNUNET_free (tmp);
64 }
65 GNUNET_free (*(gnsrecord_info->rd));
66 *(gnsrecord_info->rd) = NULL;
67 }
68 if (NULL != *(gnsrecord_info->name))
69 GNUNET_free (*(gnsrecord_info->name));
70 *(gnsrecord_info->name) = NULL;
71}
72
73
74/**
75 * Parse given JSON object to gns record
76 *
77 * @param cls closure, NULL
78 * @param root the json object representing data
79 * @param spec where to write the data
80 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
81 */
82static int
83parse_record (json_t *data, struct GNUNET_GNSRECORD_Data *rd)
84{
85 struct GNUNET_TIME_Absolute abs_exp;
86 struct GNUNET_TIME_Relative rel_exp;
87 const char *value;
88 const char *record_type;
89 int private;
90 int supplemental;
91 int is_rel_exp;
92 int shadow;
93 int unpack_state = 0;
94 json_error_t err;
95
96 // interpret single gns record
97 unpack_state = json_unpack_ex (data,
98 &err,
99 0,
100 "{s:s, s:s, s:I, s:b, s:b, s:b, s:b}",
101 GNUNET_JSON_GNSRECORD_VALUE,
102 &value,
103 GNUNET_JSON_GNSRECORD_TYPE,
104 &record_type,
105 GNUNET_JSON_GNSRECORD_RELATIVE_EXPIRATION_TIME,
106 &rel_exp.rel_value_us,
107 GNUNET_JSON_GNSRECORD_FLAG_PRIVATE,
108 &private,
109 GNUNET_JSON_GNSRECORD_FLAG_SUPPLEMENTAL,
110 &supplemental,
111 GNUNET_JSON_GNSRECORD_FLAG_RELATIVE,
112 &is_rel_exp,
113 GNUNET_JSON_GNSRECORD_FLAG_SHADOW,
114 &shadow);
115 if (0 != unpack_state)
116 {
117 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
118 "Error gnsdata object has a wrong format: `%s'!\n",
119 err.text);
120 unpack_state = json_unpack_ex (data,
121 &err,
122 0,
123 "{s:s, s:s, s:I, s:b, s:b, s:b, s:b}",
124 GNUNET_JSON_GNSRECORD_VALUE,
125 &value,
126 GNUNET_JSON_GNSRECORD_TYPE,
127 &record_type,
128 GNUNET_JSON_GNSRECORD_ABSOLUTE_EXPIRATION_TIME,
129 &abs_exp.abs_value_us,
130 GNUNET_JSON_GNSRECORD_FLAG_PRIVATE,
131 &private,
132 GNUNET_JSON_GNSRECORD_FLAG_SUPPLEMENTAL,
133 &supplemental,
134 GNUNET_JSON_GNSRECORD_FLAG_RELATIVE,
135 &is_rel_exp,
136 GNUNET_JSON_GNSRECORD_FLAG_SHADOW,
137 &shadow);
138 if ((0 != unpack_state) || (is_rel_exp))
139 {
140 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
141 "Error gnsdata object has a wrong format: `%s'!\n",
142 (is_rel_exp) ? "No relative expiration given" : err.text);
143 return GNUNET_SYSERR;
144 }
145 rd->expiration_time = abs_exp.abs_value_us;
146 }
147 else
148 {
149 rd->expiration_time = rel_exp.rel_value_us;
150 }
151 rd->record_type = GNUNET_GNSRECORD_typename_to_number (record_type);
152 if (UINT32_MAX == rd->record_type)
153 {
154 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unsupported type\n");
155 return GNUNET_SYSERR;
156 }
157 if (GNUNET_OK != GNUNET_GNSRECORD_string_to_value (rd->record_type,
158 value,
159 (void **) &rd->data,
160 &rd->data_size))
161 {
162 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Value invalid for record type\n");
163 return GNUNET_SYSERR;
164 }
165
166 if (is_rel_exp)
167 rd->flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
168 if (1 == private)
169 rd->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
170 if (1 == supplemental)
171 rd->flags |= GNUNET_GNSRECORD_RF_SUPPLEMENTAL;
172 if (1 == shadow)
173 rd->flags |= GNUNET_GNSRECORD_RF_SHADOW;
174 return GNUNET_OK;
175}
176
177
178/**
179 * Parse given JSON object to gns record
180 *
181 * @param cls closure, NULL
182 * @param root the json object representing data
183 * @param spec where to write the data
184 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
185 */
186static int
187parse_record_data (struct GnsRecordInfo *gnsrecord_info, json_t *data)
188{
189 GNUNET_assert (NULL != data);
190 if (! json_is_array (data))
191 {
192 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
193 "Error gns record data JSON is not an array!\n");
194 return GNUNET_SYSERR;
195 }
196 *(gnsrecord_info->rd_count) = json_array_size (data);
197 *(gnsrecord_info->rd) = GNUNET_malloc (sizeof(struct GNUNET_GNSRECORD_Data)
198 * json_array_size (data));
199 size_t index;
200 json_t *value;
201 json_array_foreach (data, index, value)
202 {
203 if (GNUNET_OK != parse_record (value, &(*(gnsrecord_info->rd))[index]))
204 return GNUNET_SYSERR;
205 }
206 return GNUNET_OK;
207}
208
209
210static int
211parse_gnsrecordobject (void *cls,
212 json_t *root,
213 struct GNUNET_JSON_Specification *spec)
214{
215 struct GnsRecordInfo *gnsrecord_info;
216 int unpack_state = 0;
217 const char *name;
218 json_t *data;
219
220 GNUNET_assert (NULL != root);
221 if (! json_is_object (root))
222 {
223 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
224 "Error record JSON is not an object!\n");
225 return GNUNET_SYSERR;
226 }
227 // interpret single gns record
228 unpack_state = json_unpack (root,
229 "{s:s, s:o!}",
230 GNUNET_JSON_GNSRECORD_RECORD_NAME,
231 &name,
232 GNUNET_JSON_GNSRECORD_RECORD_DATA,
233 &data);
234 if (0 != unpack_state)
235 {
236 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
237 "Error namestore records object has a wrong format!\n");
238 return GNUNET_SYSERR;
239 }
240 gnsrecord_info = (struct GnsRecordInfo *) spec->ptr;
241 *(gnsrecord_info->name) = GNUNET_strdup (name);
242 if (GNUNET_OK != parse_record_data (gnsrecord_info, data))
243 {
244 cleanup_recordinfo (gnsrecord_info);
245 return GNUNET_SYSERR;
246 }
247 return GNUNET_OK;
248}
249
250
251/**
252 * Cleanup data left from parsing the record.
253 *
254 * @param cls closure, NULL
255 * @param[out] spec where to free the data
256 */
257static void
258clean_gnsrecordobject (void *cls, struct GNUNET_JSON_Specification *spec)
259{
260 struct GnsRecordInfo *gnsrecord_info = (struct GnsRecordInfo *) spec->ptr;
261
262 GNUNET_free (gnsrecord_info);
263}
264
265
266/**
267 * JSON Specification for GNS Records.
268 *
269 * @param gnsrecord_object struct of GNUNET_GNSRECORD_Data to fill
270 * @return JSON Specification
271 */
272struct GNUNET_JSON_Specification
273GNUNET_GNSRECORD_JSON_spec_gnsrecord (struct GNUNET_GNSRECORD_Data **rd,
274 unsigned int *rd_count,
275 char **name)
276{
277 struct GnsRecordInfo *gnsrecord_info = GNUNET_new (struct GnsRecordInfo);
278
279 gnsrecord_info->rd = rd;
280 gnsrecord_info->name = name;
281 gnsrecord_info->rd_count = rd_count;
282 struct GNUNET_JSON_Specification ret = { .parser = &parse_gnsrecordobject,
283 .cleaner = &clean_gnsrecordobject,
284 .cls = NULL,
285 .field = NULL,
286 .ptr = (struct GnsRecordInfo *)
287 gnsrecord_info,
288 .ptr_size = 0,
289 .size_ptr = NULL };
290 return ret;
291}
292
293
294/**
295 * Convert GNS record to JSON.
296 *
297 * @param rname name of record
298 * @param rd record data
299 * @return corresponding JSON encoding
300 */
301json_t *
302GNUNET_GNSRECORD_JSON_from_gnsrecord (const char*rname,
303 const struct GNUNET_GNSRECORD_Data *rd,
304 unsigned int rd_count)
305{
306 const char *record_type_str;
307 char *value_str;
308 json_t *data;
309 json_t *record;
310 json_t *records;
311
312 data = json_object ();
313 if (NULL == data)
314 {
315 GNUNET_break (0);
316 return NULL;
317 }
318 if (0 !=
319 json_object_set_new (data,
320 "record_name",
321 json_string (rname)))
322 {
323 GNUNET_break (0);
324 json_decref (data);
325 return NULL;
326 }
327 records = json_array ();
328 if (NULL == records)
329 {
330 GNUNET_break (0);
331 json_decref (data);
332 return NULL;
333 }
334 for (int i = 0; i < rd_count; i++)
335 {
336 value_str = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
337 rd[i].data,
338 rd[i].data_size);
339 record_type_str = GNUNET_GNSRECORD_number_to_typename (rd[i].record_type);
340 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
341 "Packing %s %s %" PRIu64 " %d\n",
342 value_str, record_type_str, rd[i].expiration_time, rd[i].flags);
343 record = json_pack ("{s:s,s:s,s:I,s:b,s:b,s:b,s:b}",
344 GNUNET_JSON_GNSRECORD_VALUE,
345 value_str,
346 GNUNET_JSON_GNSRECORD_TYPE,
347 record_type_str,
348 (rd[i].flags
349 & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION) ?
350 GNUNET_JSON_GNSRECORD_RELATIVE_EXPIRATION_TIME :
351 GNUNET_JSON_GNSRECORD_ABSOLUTE_EXPIRATION_TIME,
352 rd[i].expiration_time,
353 GNUNET_JSON_GNSRECORD_FLAG_PRIVATE,
354 rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE,
355 GNUNET_JSON_GNSRECORD_FLAG_RELATIVE,
356 rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION,
357 GNUNET_JSON_GNSRECORD_FLAG_SUPPLEMENTAL,
358 rd[i].flags & GNUNET_GNSRECORD_RF_SUPPLEMENTAL,
359 GNUNET_JSON_GNSRECORD_FLAG_SUPPLEMENTAL,
360 rd[i].flags & GNUNET_GNSRECORD_RF_SHADOW);
361 GNUNET_free (value_str);
362 if (NULL == record)
363 {
364 GNUNET_break (0);
365 json_decref (records);
366 json_decref (data);
367 return NULL;
368 }
369 if (0 !=
370 json_array_append_new (records,
371 record))
372 {
373 GNUNET_break (0);
374 json_decref (records);
375 json_decref (data);
376 return NULL;
377 }
378 }
379 if (0 !=
380 json_object_set_new (data,
381 "data",
382 records))
383 {
384 GNUNET_break (0);
385 json_decref (data);
386 return NULL;
387 }
388 return data;
389}