aboutsummaryrefslogtreecommitdiff
path: root/src/gnsrecord/json_gnsrecord.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gnsrecord/json_gnsrecord.c')
-rw-r--r--src/gnsrecord/json_gnsrecord.c391
1 files changed, 391 insertions, 0 deletions
diff --git a/src/gnsrecord/json_gnsrecord.c b/src/gnsrecord/json_gnsrecord.c
new file mode 100644
index 000000000..068ff48c1
--- /dev/null
+++ b/src/gnsrecord/json_gnsrecord.c
@@ -0,0 +1,391 @@
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_EXPIRATION_TIME "expiration_time"
35#define GNUNET_JSON_GNSRECORD_FLAG_PRIVATE "private"
36#define GNUNET_JSON_GNSRECORD_FLAG_SUPPLEMENTAL "supplemental"
37#define GNUNET_JSON_GNSRECORD_FLAG_RELATIVE "relative_expiration"
38#define GNUNET_JSON_GNSRECORD_FLAG_SHADOW "shadow"
39#define GNUNET_JSON_GNSRECORD_RECORD_NAME "record_name"
40#define GNUNET_JSON_GNSRECORD_NEVER "never"
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_expiration_time;
86 struct GNUNET_TIME_Relative rel_expiration_time;
87 const char *value;
88 const char *record_type;
89 const char *expiration_time;
90 int private;
91 int supplemental;
92 int rel_exp;
93 int shadow;
94 int unpack_state = 0;
95
96 // interpret single gns record
97 unpack_state = json_unpack (data,
98 "{s:s, s:s, s:s, s:b, s:b, s:b, s:b}",
99 GNUNET_JSON_GNSRECORD_VALUE,
100 &value,
101 GNUNET_JSON_GNSRECORD_TYPE,
102 &record_type,
103 GNUNET_JSON_GNSRECORD_EXPIRATION_TIME,
104 &expiration_time,
105 GNUNET_JSON_GNSRECORD_FLAG_PRIVATE,
106 &private,
107 GNUNET_JSON_GNSRECORD_FLAG_SUPPLEMENTAL,
108 &supplemental,
109 GNUNET_JSON_GNSRECORD_FLAG_RELATIVE,
110 &rel_exp,
111 GNUNET_JSON_GNSRECORD_FLAG_SHADOW,
112 &shadow);
113 if (0 != unpack_state)
114 {
115 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
116 "Error gnsdata object has a wrong format!\n");
117 return GNUNET_SYSERR;
118 }
119 rd->record_type = GNUNET_GNSRECORD_typename_to_number (record_type);
120 if (UINT32_MAX == rd->record_type)
121 {
122 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unsupported type\n");
123 return GNUNET_SYSERR;
124 }
125 if (GNUNET_OK != GNUNET_GNSRECORD_string_to_value (rd->record_type,
126 value,
127 (void **) &rd->data,
128 &rd->data_size))
129 {
130 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Value invalid for record type\n");
131 return GNUNET_SYSERR;
132 }
133
134 if (0 == strcmp (expiration_time, GNUNET_JSON_GNSRECORD_NEVER))
135 {
136 rd->expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
137 }
138 else if ((1 != rel_exp) &&
139 (GNUNET_OK ==
140 GNUNET_STRINGS_fancy_time_to_absolute (expiration_time,
141 &abs_expiration_time)))
142 {
143 rd->expiration_time = abs_expiration_time.abs_value_us;
144 }
145 else if (GNUNET_OK ==
146 GNUNET_STRINGS_fancy_time_to_relative (expiration_time,
147 &rel_expiration_time))
148 {
149 rd->flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
150 rd->expiration_time = rel_expiration_time.rel_value_us;
151 }
152 else
153 {
154 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expiration time invalid\n");
155 return GNUNET_SYSERR;
156 }
157 if (1 == private)
158 rd->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
159 if (1 == supplemental)
160 rd->flags |= GNUNET_GNSRECORD_RF_SUPPLEMENTAL;
161 if (1 == shadow)
162 rd->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
163 return GNUNET_OK;
164}
165
166
167/**
168 * Parse given JSON object to gns record
169 *
170 * @param cls closure, NULL
171 * @param root the json object representing data
172 * @param spec where to write the data
173 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
174 */
175static int
176parse_record_data (struct GnsRecordInfo *gnsrecord_info, json_t *data)
177{
178 GNUNET_assert (NULL != data);
179 if (! json_is_array (data))
180 {
181 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
182 "Error gns record data JSON is not an array!\n");
183 return GNUNET_SYSERR;
184 }
185 *(gnsrecord_info->rd_count) = json_array_size (data);
186 *(gnsrecord_info->rd) = GNUNET_malloc (sizeof(struct GNUNET_GNSRECORD_Data)
187 * json_array_size (data));
188 size_t index;
189 json_t *value;
190 json_array_foreach (data, index, value)
191 {
192 if (GNUNET_OK != parse_record (value, &(*(gnsrecord_info->rd))[index]))
193 return GNUNET_SYSERR;
194 }
195 return GNUNET_OK;
196}
197
198
199static int
200parse_gnsrecordobject (void *cls,
201 json_t *root,
202 struct GNUNET_JSON_Specification *spec)
203{
204 struct GnsRecordInfo *gnsrecord_info;
205 int unpack_state = 0;
206 const char *name;
207 json_t *data;
208
209 GNUNET_assert (NULL != root);
210 if (! json_is_object (root))
211 {
212 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
213 "Error record JSON is not an object!\n");
214 return GNUNET_SYSERR;
215 }
216 // interpret single gns record
217 unpack_state = json_unpack (root,
218 "{s:s, s:o!}",
219 GNUNET_JSON_GNSRECORD_RECORD_NAME,
220 &name,
221 GNUNET_JSON_GNSRECORD_RECORD_DATA,
222 &data);
223 if (0 != unpack_state)
224 {
225 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
226 "Error namestore records object has a wrong format!\n");
227 return GNUNET_SYSERR;
228 }
229 gnsrecord_info = (struct GnsRecordInfo *) spec->ptr;
230 *(gnsrecord_info->name) = GNUNET_strdup (name);
231 if (GNUNET_OK != parse_record_data (gnsrecord_info, data))
232 {
233 cleanup_recordinfo (gnsrecord_info);
234 return GNUNET_SYSERR;
235 }
236 return GNUNET_OK;
237}
238
239
240/**
241 * Cleanup data left from parsing the record.
242 *
243 * @param cls closure, NULL
244 * @param[out] spec where to free the data
245 */
246static void
247clean_gnsrecordobject (void *cls, struct GNUNET_JSON_Specification *spec)
248{
249 struct GnsRecordInfo *gnsrecord_info = (struct GnsRecordInfo *) spec->ptr;
250
251 GNUNET_free (gnsrecord_info);
252}
253
254
255/**
256 * JSON Specification for GNS Records.
257 *
258 * @param gnsrecord_object struct of GNUNET_GNSRECORD_Data to fill
259 * @return JSON Specification
260 */
261struct GNUNET_JSON_Specification
262GNUNET_GNSRECORD_JSON_spec_gnsrecord (struct GNUNET_GNSRECORD_Data **rd,
263 unsigned int *rd_count,
264 char **name)
265{
266 struct GnsRecordInfo *gnsrecord_info = GNUNET_new (struct GnsRecordInfo);
267
268 gnsrecord_info->rd = rd;
269 gnsrecord_info->name = name;
270 gnsrecord_info->rd_count = rd_count;
271 struct GNUNET_JSON_Specification ret = { .parser = &parse_gnsrecordobject,
272 .cleaner = &clean_gnsrecordobject,
273 .cls = NULL,
274 .field = NULL,
275 .ptr = (struct GnsRecordInfo *)
276 gnsrecord_info,
277 .ptr_size = 0,
278 .size_ptr = NULL };
279 return ret;
280}
281
282
283/**
284 * Convert GNS record to JSON.
285 *
286 * @param rname name of record
287 * @param rd record data
288 * @return corresponding JSON encoding
289 */
290json_t *
291GNUNET_GNSRECORD_JSON_from_gnsrecord (const char*rname,
292 const struct GNUNET_GNSRECORD_Data *rd,
293 unsigned int rd_count)
294{
295 struct GNUNET_TIME_Absolute abs_exp;
296 struct GNUNET_TIME_Relative rel_exp;
297 const char *expiration_time_str;
298 const char *record_type_str;
299 char *value_str;
300 json_t *data;
301 json_t *record;
302 json_t *records;
303
304 data = json_object ();
305 if (NULL == data)
306 {
307 GNUNET_break (0);
308 return NULL;
309 }
310 if (0 !=
311 json_object_set_new (data,
312 "record_name",
313 json_string (rname)))
314 {
315 GNUNET_break (0);
316 json_decref (data);
317 return NULL;
318 }
319 records = json_array ();
320 if (NULL == records)
321 {
322 GNUNET_break (0);
323 json_decref (data);
324 return NULL;
325 }
326 for (int i = 0; i < rd_count; i++)
327 {
328 value_str = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
329 rd[i].data,
330 rd[i].data_size);
331 if (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION & rd[i].flags)
332 {
333 rel_exp.rel_value_us = rd[i].expiration_time;
334 expiration_time_str = GNUNET_STRINGS_relative_time_to_string (rel_exp,
335 GNUNET_NO);
336 }
337 else
338 {
339 abs_exp.abs_value_us = rd[i].expiration_time;
340 expiration_time_str = GNUNET_STRINGS_absolute_time_to_string (abs_exp);
341 }
342 record_type_str = GNUNET_GNSRECORD_number_to_typename (rd[i].record_type);
343 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
344 "Packing %s %s %s %d\n",
345 value_str, record_type_str, expiration_time_str, rd[i].flags);
346 record = json_pack ("{s:s,s:s,s:s,s:b,s:b,s:b,s:b}",
347 "value",
348 value_str,
349 "record_type",
350 record_type_str,
351 "expiration_time",
352 expiration_time_str,
353 "private",
354 rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE,
355 "relative_expiration",
356 rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION,
357 "supplemental",
358 rd[i].flags & GNUNET_GNSRECORD_RF_SUPPLEMENTAL,
359 "shadow",
360 rd[i].flags & GNUNET_GNSRECORD_RF_SHADOW_RECORD);
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}
390
391