remove 'illegal' (non-reentrant) log logic from signal handler
[oweals/gnunet.git] / src / json / json_gnsrecord.c
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
30 #define GNUNET_JSON_GNSRECORD_VALUE "value"
31 #define GNUNET_JSON_GNSRECORD_RECORD_DATA "data"
32 #define GNUNET_JSON_GNSRECORD_TYPE "record_type"
33 #define GNUNET_JSON_GNSRECORD_EXPIRATION_TIME "expiration_time"
34 #define GNUNET_JSON_GNSRECORD_FLAG "flag"
35 #define GNUNET_JSON_GNSRECORD_RECORD_NAME "record_name"
36 #define GNUNET_JSON_GNSRECORD_NEVER "never"
37
38 struct GnsRecordInfo
39 {
40   char **name;
41
42   unsigned int *rd_count;
43
44   struct GNUNET_GNSRECORD_Data **rd;
45 };
46
47
48 static void
49 cleanup_recordinfo (struct GnsRecordInfo *gnsrecord_info)
50 {
51   if (NULL != *(gnsrecord_info->rd))
52   {
53     for (int i = 0; i < *(gnsrecord_info->rd_count); i++)
54     {
55       if (NULL != (*(gnsrecord_info->rd))[i].data)
56         GNUNET_free ((char *) (*(gnsrecord_info->rd))[i].data);
57     }
58     GNUNET_free (*(gnsrecord_info->rd));
59     *(gnsrecord_info->rd) = NULL;
60   }
61   if (NULL != *(gnsrecord_info->name))
62     GNUNET_free (*(gnsrecord_info->name));
63   *(gnsrecord_info->name) = NULL;
64 }
65
66
67 /**
68  * Parse given JSON object to gns record
69  *
70  * @param cls closure, NULL
71  * @param root the json object representing data
72  * @param spec where to write the data
73  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
74  */
75 static int
76 parse_record (json_t *data, struct GNUNET_GNSRECORD_Data *rd)
77 {
78   struct GNUNET_TIME_Absolute abs_expiration_time;
79   struct GNUNET_TIME_Relative rel_expiration_time;
80   const char *value;
81   const char *record_type;
82   const char *expiration_time;
83   int flag;
84   int unpack_state = 0;
85
86   // interpret single gns record
87   unpack_state = json_unpack (data,
88                               "{s:s, s:s, s:s, s?:i!}",
89                               GNUNET_JSON_GNSRECORD_VALUE,
90                               &value,
91                               GNUNET_JSON_GNSRECORD_TYPE,
92                               &record_type,
93                               GNUNET_JSON_GNSRECORD_EXPIRATION_TIME,
94                               &expiration_time,
95                               GNUNET_JSON_GNSRECORD_FLAG,
96                               &flag);
97   if (0 != unpack_state)
98   {
99     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
100                 "Error gnsdata object has a wrong format!\n");
101     return GNUNET_SYSERR;
102   }
103   rd->record_type = GNUNET_GNSRECORD_typename_to_number (record_type);
104   if (UINT32_MAX == rd->record_type)
105   {
106     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unsupported type\n");
107     return GNUNET_SYSERR;
108   }
109   if (GNUNET_OK != GNUNET_GNSRECORD_string_to_value (rd->record_type,
110                                                      value,
111                                                      (void **) &rd->data,
112                                                      &rd->data_size))
113   {
114     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Value invalid for record type\n");
115     return GNUNET_SYSERR;
116   }
117
118   if (0 == strcmp (expiration_time, GNUNET_JSON_GNSRECORD_NEVER))
119   {
120     rd->expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
121   }
122   else if (GNUNET_OK ==
123            GNUNET_STRINGS_fancy_time_to_absolute (expiration_time,
124                                                   &abs_expiration_time))
125   {
126     rd->expiration_time = abs_expiration_time.abs_value_us;
127   }
128   else if (GNUNET_OK ==
129            GNUNET_STRINGS_fancy_time_to_relative (expiration_time,
130                                                   &rel_expiration_time))
131   {
132     rd->expiration_time = rel_expiration_time.rel_value_us;
133   }
134   else
135   {
136     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expiration time invalid\n");
137     return GNUNET_SYSERR;
138   }
139   rd->flags = (enum GNUNET_GNSRECORD_Flags) flag;
140   return GNUNET_OK;
141 }
142
143
144 /**
145  * Parse given JSON object to gns record
146  *
147  * @param cls closure, NULL
148  * @param root the json object representing data
149  * @param spec where to write the data
150  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
151  */
152 static int
153 parse_record_data (struct GnsRecordInfo *gnsrecord_info, json_t *data)
154 {
155   GNUNET_assert (NULL != data);
156   if (! json_is_array (data))
157   {
158     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
159                 "Error gns record data JSON is not an array!\n");
160     return GNUNET_SYSERR;
161   }
162   *(gnsrecord_info->rd_count) = json_array_size (data);
163   *(gnsrecord_info->rd) = GNUNET_malloc (sizeof(struct GNUNET_GNSRECORD_Data)
164                                          * json_array_size (data));
165   size_t index;
166   json_t *value;
167   json_array_foreach (data, index, value)
168   {
169     if (GNUNET_OK != parse_record (value, &(*(gnsrecord_info->rd))[index]))
170       return GNUNET_SYSERR;
171   }
172   return GNUNET_OK;
173 }
174
175
176 static int
177 parse_gnsrecordobject (void *cls,
178                        json_t *root,
179                        struct GNUNET_JSON_Specification *spec)
180 {
181   struct GnsRecordInfo *gnsrecord_info;
182   int unpack_state = 0;
183   const char *name;
184   json_t *data;
185
186   GNUNET_assert (NULL != root);
187   if (! json_is_object (root))
188   {
189     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
190                 "Error record JSON is not an object!\n");
191     return GNUNET_SYSERR;
192   }
193   // interpret single gns record
194   unpack_state = json_unpack (root,
195                               "{s:s, s:o!}",
196                               GNUNET_JSON_GNSRECORD_RECORD_NAME,
197                               &name,
198                               GNUNET_JSON_GNSRECORD_RECORD_DATA,
199                               &data);
200   if (0 != unpack_state)
201   {
202     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
203                 "Error namestore records object has a wrong format!\n");
204     return GNUNET_SYSERR;
205   }
206   gnsrecord_info = (struct GnsRecordInfo *) spec->ptr;
207   *(gnsrecord_info->name) = GNUNET_strdup (name);
208   if (GNUNET_OK != parse_record_data (gnsrecord_info, data))
209   {
210     cleanup_recordinfo (gnsrecord_info);
211     return GNUNET_SYSERR;
212   }
213   return GNUNET_OK;
214 }
215
216
217 /**
218  * Cleanup data left from parsing the record.
219  *
220  * @param cls closure, NULL
221  * @param[out] spec where to free the data
222  */
223 static void
224 clean_gnsrecordobject (void *cls, struct GNUNET_JSON_Specification *spec)
225 {
226   struct GnsRecordInfo *gnsrecord_info = (struct GnsRecordInfo *) spec->ptr;
227
228   GNUNET_free (gnsrecord_info);
229 }
230
231
232 /**
233  * JSON Specification for GNS Records.
234  *
235  * @param gnsrecord_object struct of GNUNET_GNSRECORD_Data to fill
236  * @return JSON Specification
237  */
238 struct GNUNET_JSON_Specification
239 GNUNET_JSON_spec_gnsrecord (struct GNUNET_GNSRECORD_Data **rd,
240                             unsigned int *rd_count,
241                             char **name)
242 {
243   struct GnsRecordInfo *gnsrecord_info = GNUNET_new (struct GnsRecordInfo);
244
245   gnsrecord_info->rd = rd;
246   gnsrecord_info->name = name;
247   gnsrecord_info->rd_count = rd_count;
248   struct GNUNET_JSON_Specification ret = { .parser = &parse_gnsrecordobject,
249                                            .cleaner = &clean_gnsrecordobject,
250                                            .cls = NULL,
251                                            .field = NULL,
252                                            .ptr = (struct GnsRecordInfo *)
253                                                   gnsrecord_info,
254                                            .ptr_size = 0,
255                                            .size_ptr = NULL };
256   return ret;
257 }