json_gnsrecord.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2009-2013 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file json/json_gnsrecord.c
  18. * @brief JSON handling of GNS record data
  19. * @author Philippe Buschmann
  20. */
  21. #include "platform.h"
  22. #include "gnunet_util_lib.h"
  23. #include "gnunet_json_lib.h"
  24. #define GNUNET_JSON_GNSRECORD_VALUE "value"
  25. #define GNUNET_JSON_GNSRECORD_RECORD_DATA "data"
  26. #define GNUNET_JSON_GNSRECORD_TYPE "record_type"
  27. #define GNUNET_JSON_GNSRECORD_EXPIRATION_TIME "expiration_time"
  28. #define GNUNET_JSON_GNSRECORD_FLAG "flag"
  29. #define GNUNET_JSON_GNSRECORD_RECORD_NAME "record_name"
  30. #define GNUNET_JSON_GNSRECORD_NEVER "never"
  31. struct GnsRecordInfo
  32. {
  33. char **name;
  34. unsigned int *rd_count;
  35. struct GNUNET_GNSRECORD_Data **rd;
  36. };
  37. static void
  38. cleanup_recordinfo (struct GnsRecordInfo *gnsrecord_info)
  39. {
  40. if (NULL != *(gnsrecord_info->rd))
  41. {
  42. for (int i = 0; i < *(gnsrecord_info->rd_count); i++)
  43. {
  44. if (NULL != (*(gnsrecord_info->rd))[i].data)
  45. GNUNET_free ((char *) (*(gnsrecord_info->rd))[i].data);
  46. }
  47. GNUNET_free (*(gnsrecord_info->rd));
  48. *(gnsrecord_info->rd) = NULL;
  49. }
  50. if (NULL != *(gnsrecord_info->name))
  51. GNUNET_free (*(gnsrecord_info->name));
  52. *(gnsrecord_info->name) = NULL;
  53. }
  54. /**
  55. * Parse given JSON object to gns record
  56. *
  57. * @param cls closure, NULL
  58. * @param root the json object representing data
  59. * @param spec where to write the data
  60. * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
  61. */
  62. static int
  63. parse_record (json_t *data, struct GNUNET_GNSRECORD_Data *rd)
  64. {
  65. struct GNUNET_TIME_Absolute abs_expiration_time;
  66. struct GNUNET_TIME_Relative rel_expiration_time;
  67. const char *value;
  68. const char *record_type;
  69. const char *expiration_time;
  70. int flag;
  71. int unpack_state = 0;
  72. //interpret single gns record
  73. unpack_state = json_unpack (data,
  74. "{s:s, s:s, s:s, s?:i!}",
  75. GNUNET_JSON_GNSRECORD_VALUE,
  76. &value,
  77. GNUNET_JSON_GNSRECORD_TYPE,
  78. &record_type,
  79. GNUNET_JSON_GNSRECORD_EXPIRATION_TIME,
  80. &expiration_time,
  81. GNUNET_JSON_GNSRECORD_FLAG,
  82. &flag);
  83. if (0 != unpack_state)
  84. {
  85. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  86. "Error gnsdata object has a wrong format!\n");
  87. return GNUNET_SYSERR;
  88. }
  89. rd->record_type = GNUNET_GNSRECORD_typename_to_number (record_type);
  90. if (UINT32_MAX == rd->record_type)
  91. {
  92. GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unsupported type\n");
  93. return GNUNET_SYSERR;
  94. }
  95. if (GNUNET_OK != GNUNET_GNSRECORD_string_to_value (rd->record_type,
  96. value,
  97. (void**)&rd->data,
  98. &rd->data_size))
  99. {
  100. GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Value invalid for record type\n");
  101. return GNUNET_SYSERR;
  102. }
  103. if (0 == strcmp (expiration_time, GNUNET_JSON_GNSRECORD_NEVER))
  104. {
  105. rd->expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
  106. }
  107. else if (GNUNET_OK ==
  108. GNUNET_STRINGS_fancy_time_to_absolute (expiration_time,
  109. &abs_expiration_time))
  110. {
  111. rd->expiration_time = abs_expiration_time.abs_value_us;
  112. }
  113. else if (GNUNET_OK ==
  114. GNUNET_STRINGS_fancy_time_to_relative (expiration_time,
  115. &rel_expiration_time))
  116. {
  117. rd->expiration_time = rel_expiration_time.rel_value_us;
  118. }
  119. else
  120. {
  121. GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expiration time invalid\n");
  122. return GNUNET_SYSERR;
  123. }
  124. rd->flags = (enum GNUNET_GNSRECORD_Flags) flag;
  125. return GNUNET_OK;
  126. }
  127. /**
  128. * Parse given JSON object to gns record
  129. *
  130. * @param cls closure, NULL
  131. * @param root the json object representing data
  132. * @param spec where to write the data
  133. * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
  134. */
  135. static int
  136. parse_record_data (struct GnsRecordInfo *gnsrecord_info, json_t *data)
  137. {
  138. GNUNET_assert (NULL != data);
  139. if (! json_is_array (data))
  140. {
  141. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  142. "Error gns record data JSON is not an array!\n");
  143. return GNUNET_SYSERR;
  144. }
  145. *(gnsrecord_info->rd_count) = json_array_size (data);
  146. *(gnsrecord_info->rd) = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Data) *
  147. json_array_size (data));
  148. size_t index;
  149. json_t *value;
  150. json_array_foreach (data, index, value)
  151. {
  152. if (GNUNET_OK != parse_record (value, &(*(gnsrecord_info->rd))[index]))
  153. return GNUNET_SYSERR;
  154. }
  155. return GNUNET_OK;
  156. }
  157. static int
  158. parse_gnsrecordobject (void *cls,
  159. json_t *root,
  160. struct GNUNET_JSON_Specification *spec)
  161. {
  162. struct GnsRecordInfo *gnsrecord_info;
  163. int unpack_state = 0;
  164. const char *name;
  165. json_t *data;
  166. GNUNET_assert (NULL != root);
  167. if (! json_is_object (root))
  168. {
  169. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  170. "Error record JSON is not an object!\n");
  171. return GNUNET_SYSERR;
  172. }
  173. //interpret single gns record
  174. unpack_state = json_unpack (root,
  175. "{s:s, s:o!}",
  176. GNUNET_JSON_GNSRECORD_RECORD_NAME,
  177. &name,
  178. GNUNET_JSON_GNSRECORD_RECORD_DATA,
  179. &data);
  180. if (0 != unpack_state)
  181. {
  182. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  183. "Error namestore records object has a wrong format!\n");
  184. return GNUNET_SYSERR;
  185. }
  186. gnsrecord_info = (struct GnsRecordInfo *) spec->ptr;
  187. *(gnsrecord_info->name) = GNUNET_strdup (name);
  188. if (GNUNET_OK != parse_record_data (gnsrecord_info, data))
  189. {
  190. cleanup_recordinfo (gnsrecord_info);
  191. return GNUNET_SYSERR;
  192. }
  193. return GNUNET_OK;
  194. }
  195. /**
  196. * Cleanup data left from parsing the record.
  197. *
  198. * @param cls closure, NULL
  199. * @param[out] spec where to free the data
  200. */
  201. static void
  202. clean_gnsrecordobject (void *cls, struct GNUNET_JSON_Specification *spec)
  203. {
  204. struct GnsRecordInfo *gnsrecord_info = (struct GnsRecordInfo *) spec->ptr;
  205. GNUNET_free (gnsrecord_info);
  206. }
  207. /**
  208. * JSON Specification for GNS Records.
  209. *
  210. * @param gnsrecord_object struct of GNUNET_GNSRECORD_Data to fill
  211. * @return JSON Specification
  212. */
  213. struct GNUNET_JSON_Specification
  214. GNUNET_JSON_spec_gnsrecord (struct GNUNET_GNSRECORD_Data **rd,
  215. unsigned int *rd_count,
  216. char **name)
  217. {
  218. struct GnsRecordInfo *gnsrecord_info = GNUNET_new (struct GnsRecordInfo);
  219. gnsrecord_info->rd = rd;
  220. gnsrecord_info->name = name;
  221. gnsrecord_info->rd_count = rd_count;
  222. struct GNUNET_JSON_Specification ret = {.parser = &parse_gnsrecordobject,
  223. .cleaner = &clean_gnsrecordobject,
  224. .cls = NULL,
  225. .field = NULL,
  226. .ptr = (struct GnsRecordInfo *)
  227. gnsrecord_info,
  228. .ptr_size = 0,
  229. .size_ptr = NULL};
  230. return ret;
  231. }