aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhil <phil.buschmann@tum.de>2018-07-26 02:31:30 +0200
committerPhil <phil.buschmann@tum.de>2018-07-26 02:31:30 +0200
commitf7ca27a73e69a8c224d65768be3416ff1388c1d7 (patch)
tree7530a6def74a55885780285162b18b4c2b353380
parentcc577a227d6a5ae8ef75e0fa91ef98ced2d2b743 (diff)
downloadgnunet-f7ca27a73e69a8c224d65768be3416ff1388c1d7.tar.gz
gnunet-f7ca27a73e69a8c224d65768be3416ff1388c1d7.zip
change namestore, json handling; fix identity, gns
-rw-r--r--src/gns/plugin_rest_gns.c81
-rw-r--r--src/gns/plugin_rest_gns2.c717
-rw-r--r--src/gnsrecord/Makefile.am1
-rw-r--r--src/gnsrecord/gnsrecord.c126
-rw-r--r--src/identity/plugin_rest_identity.c4
-rw-r--r--src/include/gnunet_gnsrecord_lib.h8
-rw-r--r--src/include/gnunet_json_lib.h22
-rw-r--r--src/json/Makefile.am3
-rw-r--r--src/json/json_generator.c35
-rw-r--r--src/json/json_gnsrecord.c163
-rw-r--r--src/namestore/plugin_rest_namestore.c225
-rw-r--r--src/namestore/plugin_rest_namestore2.c1229
12 files changed, 340 insertions, 2274 deletions
diff --git a/src/gns/plugin_rest_gns.c b/src/gns/plugin_rest_gns.c
index 22c908275..aae14153d 100644
--- a/src/gns/plugin_rest_gns.c
+++ b/src/gns/plugin_rest_gns.c
@@ -2,20 +2,18 @@
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 GNUnet e.V. 3 Copyright (C) 2012-2015 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software: you can redistribute it and/or modify it
6 it under the terms of the GNU General Public License as published 6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation; either version 3, or (at your 7 by the Free Software Foundation, either version 3 of the License,
8 option) any later version. 8 or (at your option) any later version.
9 9
10 GNUnet is distributed in the hope that it will be useful, but 10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU General Public License 15 You should have received a copy of the GNU Affero General Public License
16 along with GNUnet; see the file COPYING. If not, write to the 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19 */ 17 */
20/** 18/**
21 * @author Philippe Buschmann 19 * @author Philippe Buschmann
@@ -36,6 +34,7 @@
36#define GNUNET_REST_PARAMETER_GNS_NAME "name" 34#define GNUNET_REST_PARAMETER_GNS_NAME "name"
37 35
38#define GNUNET_REST_PARAMETER_GNS_RECORD_TYPE "record_type" 36#define GNUNET_REST_PARAMETER_GNS_RECORD_TYPE "record_type"
37#define GNUNET_REST_GNS_ERROR_UNKNOWN "Unknown Error"
39 38
40/** 39/**
41 * The configuration handle 40 * The configuration handle
@@ -128,8 +127,9 @@ struct RequestHandle
128 * @param handle Handle to clean up 127 * @param handle Handle to clean up
129 */ 128 */
130static void 129static void
131cleanup_handle (struct RequestHandle *handle) 130cleanup_handle (void *cls)
132{ 131{
132 struct RequestHandle *handle = cls;
133 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 133 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
134 "Cleaning up\n"); 134 "Cleaning up\n");
135 135
@@ -170,20 +170,22 @@ do_error (void *cls)
170{ 170{
171 struct RequestHandle *handle = cls; 171 struct RequestHandle *handle = cls;
172 struct MHD_Response *resp; 172 struct MHD_Response *resp;
173 char *json_error; 173 json_t *json_error = json_object();
174 char *response;
174 175
175 if (NULL == handle->emsg) 176 if (NULL == handle->emsg)
176 handle->emsg = GNUNET_strdup("Unknown Error"); 177 handle->emsg = GNUNET_strdup(GNUNET_REST_GNS_ERROR_UNKNOWN);
178
179 json_object_set_new(json_error,"error", json_string(handle->emsg));
177 180
178 GNUNET_asprintf (&json_error, "{\"error\": \"%s\"}", handle->emsg);
179
180 if (0 == handle->response_code) 181 if (0 == handle->response_code)
181 handle->response_code = MHD_HTTP_OK; 182 handle->response_code = MHD_HTTP_OK;
182 183 response = json_dumps (json_error, 0);
183 resp = GNUNET_REST_create_response (json_error); 184 resp = GNUNET_REST_create_response (response);
184 handle->proc (handle->proc_cls, resp, handle->response_code); 185 handle->proc (handle->proc_cls, resp, handle->response_code);
185 cleanup_handle (handle); 186 json_decref(json_error);
186 GNUNET_free(json_error); 187 GNUNET_free(response);
188 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
187} 189}
188 190
189 191
@@ -201,6 +203,7 @@ handle_gns_response (void *cls,
201 uint32_t rd_count, 203 uint32_t rd_count,
202 const struct GNUNET_GNSRECORD_Data *rd) 204 const struct GNUNET_GNSRECORD_Data *rd)
203{ 205{
206 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "TEST4\n");
204 struct RequestHandle *handle = cls; 207 struct RequestHandle *handle = cls;
205 struct MHD_Response *resp; 208 struct MHD_Response *resp;
206 json_t *result_array; 209 json_t *result_array;
@@ -216,12 +219,6 @@ handle_gns_response (void *cls,
216 GNUNET_SCHEDULER_add_now (&do_error, handle); 219 GNUNET_SCHEDULER_add_now (&do_error, handle);
217 return; 220 return;
218 } 221 }
219 if (0 == rd_count)
220 {
221 handle->emsg = GNUNET_strdup("No result found");
222 GNUNET_SCHEDULER_add_now (&do_error, handle);
223 return;
224 }
225 222
226 result_array = json_array(); 223 result_array = json_array();
227 for (uint32_t i=0;i<rd_count;i++) 224 for (uint32_t i=0;i<rd_count;i++)
@@ -246,7 +243,7 @@ handle_gns_response (void *cls,
246 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); 243 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
247 GNUNET_free (result); 244 GNUNET_free (result);
248 json_decref (result_array); 245 json_decref (result_array);
249 cleanup_handle (handle); 246 GNUNET_SCHEDULER_add_now(&cleanup_handle, handle);
250} 247}
251 248
252 249
@@ -264,7 +261,8 @@ get_gns_cont (struct GNUNET_REST_RequestHandle *con_handle,
264{ 261{
265 struct RequestHandle *handle = cls; 262 struct RequestHandle *handle = cls;
266 struct GNUNET_HashCode key; 263 struct GNUNET_HashCode key;
267 int conversion_state; 264 char *record_type;
265 char *name;
268 266
269 GNUNET_CRYPTO_hash (GNUNET_REST_PARAMETER_GNS_NAME, 267 GNUNET_CRYPTO_hash (GNUNET_REST_PARAMETER_GNS_NAME,
270 strlen (GNUNET_REST_PARAMETER_GNS_NAME), 268 strlen (GNUNET_REST_PARAMETER_GNS_NAME),
@@ -277,8 +275,14 @@ get_gns_cont (struct GNUNET_REST_RequestHandle *con_handle,
277 GNUNET_SCHEDULER_add_now (&do_error, handle); 275 GNUNET_SCHEDULER_add_now (&do_error, handle);
278 return; 276 return;
279 } 277 }
280 handle->name = GNUNET_strdup( 278 name = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map,&key);
281 GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map,&key)); 279 if(0 >= strlen (name))
280 {
281 handle->emsg = GNUNET_strdup("Length of parameter name is zero");
282 GNUNET_SCHEDULER_add_now (&do_error, handle);
283 return;
284 }
285 handle->name = GNUNET_strdup(name);
282 286
283 GNUNET_CRYPTO_hash (GNUNET_REST_PARAMETER_GNS_RECORD_TYPE, 287 GNUNET_CRYPTO_hash (GNUNET_REST_PARAMETER_GNS_RECORD_TYPE,
284 strlen (GNUNET_REST_PARAMETER_GNS_RECORD_TYPE), 288 strlen (GNUNET_REST_PARAMETER_GNS_RECORD_TYPE),
@@ -291,11 +295,13 @@ get_gns_cont (struct GNUNET_REST_RequestHandle *con_handle,
291 GNUNET_SCHEDULER_add_now (&do_error, handle); 295 GNUNET_SCHEDULER_add_now (&do_error, handle);
292 return; 296 return;
293 } 297 }
294 conversion_state = sscanf (
295 GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, &key),"%u",
296 &(handle->record_type));
297 298
298 if((EOF == conversion_state) || (0 == conversion_state)) 299
300 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "TEST1\n");
301
302 record_type = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, &key);
303 handle->record_type = GNUNET_GNSRECORD_typename_to_number(record_type);
304 if(UINT32_MAX == handle->record_type)
299 { 305 {
300 handle->record_type = GNUNET_GNSRECORD_TYPE_ANY; 306 handle->record_type = GNUNET_GNSRECORD_TYPE_ANY;
301 } 307 }
@@ -307,6 +313,7 @@ get_gns_cont (struct GNUNET_REST_RequestHandle *con_handle,
307 GNUNET_SCHEDULER_add_now (&do_error, handle); 313 GNUNET_SCHEDULER_add_now (&do_error, handle);
308 return; 314 return;
309 } 315 }
316 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "TEST2\n");
310 317
311 handle->gns_lookup = GNUNET_GNS_lookup_with_tld (handle->gns, 318 handle->gns_lookup = GNUNET_GNS_lookup_with_tld (handle->gns,
312 handle->name, 319 handle->name,
@@ -314,13 +321,7 @@ get_gns_cont (struct GNUNET_REST_RequestHandle *con_handle,
314 GNUNET_NO, 321 GNUNET_NO,
315 &handle_gns_response, 322 &handle_gns_response,
316 handle); 323 handle);
317 324 return;
318 if (NULL == handle->gns_lookup)
319 {
320 handle->emsg = GNUNET_strdup("GNS lookup failed");
321 GNUNET_SCHEDULER_add_now (&do_error, handle);
322 return;
323 }
324} 325}
325 326
326 327
@@ -346,7 +347,7 @@ options_cont (struct GNUNET_REST_RequestHandle *con_handle,
346 "Access-Control-Allow-Methods", 347 "Access-Control-Allow-Methods",
347 allow_methods); 348 allow_methods);
348 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); 349 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
349 cleanup_handle (handle); 350 GNUNET_SCHEDULER_add_now(&cleanup_handle, handle);
350 return; 351 return;
351} 352}
352 353
diff --git a/src/gns/plugin_rest_gns2.c b/src/gns/plugin_rest_gns2.c
deleted file mode 100644
index 82d62744c..000000000
--- a/src/gns/plugin_rest_gns2.c
+++ /dev/null
@@ -1,717 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 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/**
19 * @author Martin Schanzenbach
20 * @author Philippe Buschmann
21 * @file gns/plugin_rest_gns.c
22 * @brief GNUnet GNS REST plugin
23 *
24 */
25
26#include "platform.h"
27#include "gnunet_rest_plugin.h"
28#include <gnunet_dnsparser_lib.h>
29#include <gnunet_identity_service.h>
30#include <gnunet_gnsrecord_lib.h>
31#include <gnunet_namestore_service.h>
32#include <gnunet_gns_service.h>
33#include <gnunet_rest_lib.h>
34#include <gnunet_jsonapi_lib.h>
35#include <gnunet_jsonapi_util.h>
36#include <jansson.h>
37
38#define GNUNET_REST_API_NS_GNS "/gns"
39
40#define GNUNET_REST_JSONAPI_GNS_RECORD_TYPE "record_type"
41
42#define GNUNET_REST_PARAMETER_GNS_NAME "name"
43
44#define GNUNET_REST_JSONAPI_GNS_TYPEINFO "gns_name"
45
46#define GNUNET_REST_JSONAPI_GNS_RECORD "records"
47
48#define GNUNET_REST_JSONAPI_GNS_EGO "ego"
49
50#define GNUNET_REST_JSONAPI_GNS_PKEY "pkey"
51
52#define GNUNET_REST_JSONAPI_GNS_OPTIONS "options"
53
54/**
55 * @brief struct returned by the initialization function of the plugin
56 */
57struct Plugin
58{
59 const struct GNUNET_CONFIGURATION_Handle *cfg;
60};
61
62const struct GNUNET_CONFIGURATION_Handle *cfg;
63
64struct LookupHandle
65{
66 /**
67 * Handle to GNS service.
68 */
69 struct GNUNET_GNS_Handle *gns;
70
71 /**
72 * Desired timeout for the lookup (default is no timeout).
73 */
74 struct GNUNET_TIME_Relative timeout;
75
76 /**
77 * Handle to lookup request
78 */
79 struct GNUNET_GNS_LookupRequest *lookup_request;
80
81 /**
82 * Handle to rest request
83 */
84 struct GNUNET_REST_RequestHandle *rest_handle;
85
86 /**
87 * Lookup an ego with the identity service.
88 */
89 struct GNUNET_IDENTITY_EgoLookup *el;
90
91 /**
92 * Handle for identity service.
93 */
94 struct GNUNET_IDENTITY_Handle *identity;
95
96 /**
97 * Active operation on identity service.
98 */
99 struct GNUNET_IDENTITY_Operation *id_op;
100
101 /**
102 * ID of a task associated with the resolution process.
103 */
104 struct GNUNET_SCHEDULER_Task * timeout_task;
105
106 /**
107 * The root of the received JSON or NULL
108 */
109 json_t *json_root;
110
111 /**
112 * The plugin result processor
113 */
114 GNUNET_REST_ResultProcessor proc;
115
116 /**
117 * The closure of the result processor
118 */
119 void *proc_cls;
120
121 /**
122 * The name to look up
123 */
124 char *name;
125
126 /**
127 * The ego to use
128 * In string representation from JSON
129 */
130 const char *ego_str;
131
132 /**
133 * The Pkey to use
134 * In string representation from JSON
135 */
136 const char *pkey_str;
137
138 /**
139 * The record type
140 */
141 int type;
142
143 /**
144 * The public key of to use for lookup
145 */
146 struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
147
148 /**
149 * The public key to use for lookup
150 */
151 struct GNUNET_CRYPTO_EcdsaPublicKey pkeym;
152
153 /**
154 * The resolver options
155 */
156 enum GNUNET_GNS_LocalOptions options;
157
158 /**
159 * the shorten key
160 */
161 struct GNUNET_CRYPTO_EcdsaPrivateKey shorten_key;
162
163 /**
164 * HTTP response code
165 */
166 int response_code;
167
168 /**
169 * HTTP response code
170 */
171 char* emsg;
172
173};
174
175
176/**
177 * Cleanup lookup handle.
178 *
179 * @param handle Handle to clean up
180 */
181static void
182cleanup_handle (struct LookupHandle *handle)
183{
184 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
185 "Cleaning up\n");
186 if (NULL != handle->json_root)
187 json_decref (handle->json_root);
188
189 if (NULL != handle->name)
190 GNUNET_free (handle->name);
191 if (NULL != handle->emsg)
192 GNUNET_free (handle->emsg);
193 if (NULL != handle->el)
194 {
195 GNUNET_IDENTITY_ego_lookup_cancel (handle->el);
196 handle->el = NULL;
197 }
198 if (NULL != handle->id_op)
199 {
200 GNUNET_IDENTITY_cancel (handle->id_op);
201 handle->id_op = NULL;
202 }
203 if (NULL != handle->lookup_request)
204 {
205 GNUNET_GNS_lookup_cancel (handle->lookup_request);
206 handle->lookup_request = NULL;
207 }
208 if (NULL != handle->identity)
209 {
210 GNUNET_IDENTITY_disconnect (handle->identity);
211 handle->identity = NULL;
212 }
213 if (NULL != handle->gns)
214 {
215 GNUNET_GNS_disconnect (handle->gns);
216 handle->gns = NULL;
217 }
218
219 if (NULL != handle->timeout_task)
220 {
221 GNUNET_SCHEDULER_cancel (handle->timeout_task);
222 }
223 GNUNET_free (handle);
224}
225
226
227/**
228 * Task run on shutdown. Cleans up everything.
229 *
230 * @param cls unused
231 * @param tc scheduler context
232 */
233static void
234do_error (void *cls)
235{
236 struct LookupHandle *handle = cls;
237 struct MHD_Response *resp;
238 char *json_error;
239
240 if (NULL == handle->emsg)
241 handle->emsg = GNUNET_strdup("Unknown Error");
242
243 GNUNET_asprintf (&json_error, "{\"error\": \"%s\"}", handle->emsg);
244 handle->response_code = MHD_HTTP_OK;
245
246 resp = GNUNET_REST_create_response (json_error);
247 handle->proc (handle->proc_cls, resp, handle->response_code);
248 cleanup_handle (handle);
249 GNUNET_free(json_error);
250}
251
252
253/**
254 * Create json representation of a GNSRECORD
255 *
256 * @param rd the GNSRECORD_Data
257 */
258static json_t *
259gnsrecord_to_json (const struct GNUNET_GNSRECORD_Data *rd)
260{
261 const char *typename;
262 char *string_val;
263 const char *exp_str;
264 json_t *record_obj;
265
266 typename = GNUNET_GNSRECORD_number_to_typename (rd->record_type);
267 string_val = GNUNET_GNSRECORD_value_to_string (rd->record_type,
268 rd->data,
269 rd->data_size);
270
271 if (NULL == string_val)
272 {
273 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
274 "Record of type %d malformed, skipping\n",
275 (int) rd->record_type);
276 return NULL;
277 }
278 record_obj = json_object ();
279 json_object_set_new (record_obj, "type", json_string (typename));
280 json_object_set_new (record_obj, "value", json_string (string_val));
281 GNUNET_free (string_val);
282
283 if (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION & rd->flags)
284 {
285 struct GNUNET_TIME_Relative time_rel;
286 time_rel.rel_value_us = rd->expiration_time;
287 exp_str = GNUNET_STRINGS_relative_time_to_string (time_rel, 1);
288 }
289 else
290 {
291 struct GNUNET_TIME_Absolute time_abs;
292 time_abs.abs_value_us = rd->expiration_time;
293 exp_str = GNUNET_STRINGS_absolute_time_to_string (time_abs);
294 }
295 json_object_set_new (record_obj, "expiration_time", json_string (exp_str));
296
297 json_object_set_new (record_obj, "expired",
298 json_boolean (GNUNET_YES == GNUNET_GNSRECORD_is_expired (rd)));
299 return record_obj;
300}
301
302/**
303 * Function called with the result of a GNS lookup.
304 *
305 * @param cls the 'const char *' name that was resolved
306 * @param rd_count number of records returned
307 * @param rd array of @a rd_count records with the results
308 */
309static void
310process_lookup_result (void *cls, uint32_t rd_count,
311 const struct GNUNET_GNSRECORD_Data *rd)
312{
313 struct LookupHandle *handle = cls;
314 struct MHD_Response *resp;
315 uint32_t i;
316 char *result;
317 json_t *result_array;
318 json_t *record_obj;
319
320 result_array = json_array();
321 handle->lookup_request = NULL;
322 for (i=0; i<rd_count; i++)
323 {
324 if ( (rd[i].record_type != handle->type) &&
325 (GNUNET_GNSRECORD_TYPE_ANY != handle->type) )
326 continue;
327 record_obj = gnsrecord_to_json (&(rd[i]));
328 json_array_append (result_array, record_obj);
329 json_decref (record_obj);
330 }
331 result = json_dumps(result_array, 0);
332 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result);
333 resp = GNUNET_REST_create_response (result);
334 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
335 GNUNET_free (result);
336 json_decref (result_array);
337 cleanup_handle (handle);
338}
339
340
341/**
342 * Perform the actual resolution, starting with the zone
343 * identified by the given public key and the shorten zone.
344 *
345 * @param pkey public key to use for the zone, can be NULL
346 */
347static void
348lookup_with_public_key (struct LookupHandle *handle)
349{
350 if (UINT32_MAX == handle->type)
351 {
352 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
353 _("Invalid typename specified, assuming `ANY'\n"));
354 handle->type = GNUNET_GNSRECORD_TYPE_ANY;
355 }
356 if (NULL != handle->name)
357 {
358 handle->lookup_request = GNUNET_GNS_lookup (handle->gns,
359 handle->name,
360 &handle->pkey,
361 handle->type,
362 handle->options,
363 &process_lookup_result,
364 handle);
365 }
366 else
367 {
368 handle->emsg = GNUNET_strdup("Parameter name is missing");
369 GNUNET_SCHEDULER_add_now (&do_error, handle);
370 return;
371 }
372}
373
374
375/**
376 * Method called to with the ego we are to use for the lookup,
377 * when the ego is determined by a name.
378 *
379 * @param cls closure (NULL, unused)
380 * @param ego ego handle, NULL if not found
381 */
382static void
383identity_zone_cb (void *cls,
384 const struct GNUNET_IDENTITY_Ego *ego)
385{
386 struct LookupHandle *handle = cls;
387
388 handle->el = NULL;
389 if (NULL == ego)
390 {
391 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
392 _("Ego for not found, cannot perform lookup.\n"));
393 handle->emsg = GNUNET_strdup ("Ego for not found, cannot perform lookup.");
394 GNUNET_SCHEDULER_add_now (&do_error, handle);
395 return;
396 }
397 else
398 {
399 GNUNET_IDENTITY_ego_get_public_key (ego, &handle->pkey);
400 lookup_with_public_key (handle);
401 }
402 json_decref(handle->json_root);
403}
404
405
406/**
407 * Method called to with the ego we are to use for the lookup,
408 * when the ego is the one for the default master zone.
409 *
410 * @param cls closure (NULL, unused)
411 * @param ego ego handle, NULL if not found
412 * @param ctx context for application to store data for this ego
413 * (during the lifetime of this process, initially NULL)
414 * @param name name assigned by the user for this ego,
415 * NULL if the user just deleted the ego and it
416 * must thus no longer be used
417 */
418static void
419identity_master_cb (void *cls,
420 struct GNUNET_IDENTITY_Ego *ego,
421 void **ctx,
422 const char *name)
423{
424 const char *dot;
425 struct LookupHandle *handle = cls;
426
427 handle->id_op = NULL;
428 if (NULL == ego)
429 {
430 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
431 _("Ego for `gns-master' not found, cannot perform lookup. Did you run gnunet-gns-import.sh?\n"));
432 handle->emsg = GNUNET_strdup("Ego for `gns-master' not found, cannot perform lookup. Did you run gnunet-gns-import.sh?");
433 GNUNET_SCHEDULER_add_now (&do_error, handle);
434 return;
435 }
436 GNUNET_IDENTITY_ego_get_public_key (ego,
437 &handle->pkey);
438 /* main name is our own master zone, do no look for that in the DHT */
439 handle->options = GNUNET_GNS_LO_LOCAL_MASTER;
440 /* if the name is of the form 'label.gnu', never go to the DHT */
441 dot = NULL;
442 if (NULL != handle->name)
443 dot = strchr (handle->name, '.');
444 if ( (NULL != dot) &&
445 (0 == strcasecmp (dot, ".gnu")) )
446 handle->options = GNUNET_GNS_LO_NO_DHT;
447 lookup_with_public_key (handle);
448}
449
450/**
451 * Handle get request
452 *
453 * @param handle the lookup handle
454 */
455static void
456get_gns_cont (struct GNUNET_REST_RequestHandle *conndata_handle,
457 const char* url,
458 void *cls)
459{
460 struct LookupHandle *handle = cls;
461 struct GNUNET_HashCode key;
462 long int enum_test;
463 char *temp_val;
464
465 //check for /gns otherwise 404
466 if (strlen (GNUNET_REST_API_NS_GNS) > strlen (url))
467 {
468 handle->emsg = GNUNET_strdup("Wrong URL");
469 GNUNET_SCHEDULER_add_now (&do_error, handle);
470 return;
471 }
472
473 //connect to gns
474 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
475 handle->gns = GNUNET_GNS_connect (cfg);
476 handle->identity = GNUNET_IDENTITY_connect (cfg, NULL, NULL);
477 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
478 &do_error, handle);
479 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
480 if (NULL == handle->gns)
481 {
482 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Connecting to GNS failed\n");
483 handle->emsg = GNUNET_strdup("Connecting to GNS failed");
484 GNUNET_SCHEDULER_add_now (&do_error, handle);
485 return;
486 }
487
488 //check parameter name -> BAD_REQUEST
489 GNUNET_CRYPTO_hash (GNUNET_REST_PARAMETER_GNS_NAME,
490 strlen (GNUNET_REST_PARAMETER_GNS_NAME),
491 &key);
492 if ( GNUNET_NO
493 == GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
494 &key))
495 {
496 handle->emsg = GNUNET_strdup("Parameter name is missing");
497 GNUNET_SCHEDULER_add_now (&do_error, handle);
498 return;
499 }
500 handle->name = GNUNET_strdup(GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
501 &key));
502
503 //check parameter record_type, optional
504 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_GNS_RECORD_TYPE,
505 strlen (GNUNET_REST_JSONAPI_GNS_RECORD_TYPE),
506 &key);
507 if ( GNUNET_YES ==
508 GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
509 &key) )
510 {
511 handle->type = GNUNET_GNSRECORD_typename_to_number(
512 GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
513 &key));
514 }
515 else
516 {
517 handle->type = GNUNET_GNSRECORD_TYPE_ANY;
518 }
519
520 //check parameter options, optional
521 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_GNS_OPTIONS,
522 strlen (GNUNET_REST_JSONAPI_GNS_OPTIONS),
523 &key);
524 handle->options = GNUNET_GNS_LO_DEFAULT;
525 if ( GNUNET_YES
526 == GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
527 &key))
528 {
529 temp_val = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map, &key);
530 if (1 < strlen(temp_val))
531 {
532 handle->options = GNUNET_GNS_LO_DEFAULT;
533 }
534 else
535 {
536 //atoi because no valid conversion is default local option
537 enum_test = atoi(temp_val);
538 if (2 < enum_test)
539 handle->options = GNUNET_GNS_LO_DEFAULT;
540 else
541 handle->options = enum_test;
542 }
543 }
544 else
545 handle->options = GNUNET_GNS_LO_DEFAULT;
546
547 //check parameter pkey, shortcut to lookup
548 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_GNS_PKEY,
549 strlen (GNUNET_REST_JSONAPI_GNS_PKEY),
550 &key);
551 if ( GNUNET_YES
552 == GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
553 &key))
554 {
555 handle->pkey_str = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
556 &key);
557 GNUNET_assert(NULL != handle->pkey_str);
558 if (GNUNET_OK
559 != GNUNET_CRYPTO_ecdsa_public_key_from_string (
560 handle->pkey_str, strlen (handle->pkey_str), &(handle->pkey)))
561 {
562 handle->emsg = GNUNET_strdup("Parameter pkey has a wrong format");
563 GNUNET_SCHEDULER_add_now (&do_error, handle);
564 return;
565 }
566 lookup_with_public_key (handle);
567 return;
568 }
569
570 //check parameter ego, lookup public key of ego
571 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_GNS_EGO,
572 strlen (GNUNET_REST_JSONAPI_GNS_EGO),
573 &key);
574 if ( GNUNET_YES ==
575 GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
576 &key) )
577 {
578 handle->ego_str = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
579 &key);
580 handle->el = GNUNET_IDENTITY_ego_lookup (cfg,
581 handle->ego_str,
582 &identity_zone_cb,
583 handle);
584 return;
585 }
586
587 //if name ends with .zkey then get public key
588 if ( (NULL != handle->name) &&
589 (strlen (handle->name) > 4) &&
590 (0 == strcmp (".zkey",
591 &handle->name[strlen (handle->name) - 4])) )
592 {
593 GNUNET_CRYPTO_ecdsa_key_get_public( GNUNET_CRYPTO_ecdsa_key_get_anonymous (),
594 &(handle->pkey));
595 lookup_with_public_key (handle);
596 }
597 else //else use gns-master identity
598 {
599 handle->id_op = GNUNET_IDENTITY_get (handle->identity,
600 "gns-master",
601 &identity_master_cb,
602 handle);
603 }
604}
605
606/**
607 * Handle rest request
608 *
609 * @param handle the lookup handle
610 */
611static void
612options_cont (struct GNUNET_REST_RequestHandle *con_handle,
613 const char* url,
614 void *cls)
615{
616 struct MHD_Response *resp;
617 struct LookupHandle *handle = cls;
618
619 //For GNS, independent of path return all options
620 resp = GNUNET_REST_create_response (NULL);
621 MHD_add_response_header (resp,
622 "Access-Control-Allow-Methods",
623 MHD_HTTP_METHOD_GET);
624 handle->proc (handle->proc_cls,
625 resp,
626 MHD_HTTP_OK);
627 cleanup_handle (handle);
628}
629
630
631/**
632 * Function processing the REST call
633 *
634 * @param method HTTP method
635 * @param url URL of the HTTP request
636 * @param data body of the HTTP request (optional)
637 * @param data_size length of the body
638 * @param proc callback function for the result
639 * @param proc_cls closure for @a proc
640 * @return #GNUNET_OK if request accepted
641 */
642static void
643rest_gns_process_request (struct GNUNET_REST_RequestHandle *conndata_handle,
644 GNUNET_REST_ResultProcessor proc,
645 void *proc_cls)
646{
647 static const struct GNUNET_REST_RequestHandler handlers[] = {
648 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_GNS, &get_gns_cont},
649 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_GNS, &options_cont},
650 GNUNET_REST_HANDLER_END
651 };
652 struct LookupHandle *handle = GNUNET_new (struct LookupHandle);
653 struct GNUNET_REST_RequestHandlerError err;
654
655 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
656 handle->proc_cls = proc_cls;
657 handle->proc = proc;
658 handle->rest_handle = conndata_handle;
659
660 if (GNUNET_NO == GNUNET_REST_handle_request (conndata_handle,
661 handlers,
662 &err,
663 handle))
664 {
665 handle->response_code = err.error_code;
666 GNUNET_SCHEDULER_add_now (&do_error, handle);
667 }
668}
669
670
671/**
672 * Entry point for the plugin.
673 *
674 * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
675 * @return NULL on error, otherwise the plugin context
676 */
677void *
678libgnunet_plugin_rest_gns_init (void *cls)
679{
680 static struct Plugin plugin;
681 cfg = cls;
682 struct GNUNET_REST_Plugin *api;
683
684 if (NULL != plugin.cfg)
685 return NULL; /* can only initialize once! */
686 memset (&plugin, 0, sizeof (struct Plugin));
687 plugin.cfg = cfg;
688 api = GNUNET_new (struct GNUNET_REST_Plugin);
689 api->cls = &plugin;
690 api->name = GNUNET_REST_API_NS_GNS;
691 api->process_request = &rest_gns_process_request;
692 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
693 _("GNS REST API initialized\n"));
694 return api;
695}
696
697
698/**
699 * Exit point from the plugin.
700 *
701 * @param cls the plugin context (as returned by "init")
702 * @return always NULL
703 */
704void *
705libgnunet_plugin_rest_gns_done (void *cls)
706{
707 struct GNUNET_REST_Plugin *api = cls;
708 struct Plugin *plugin = api->cls;
709
710 plugin->cfg = NULL;
711 GNUNET_free (api);
712 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
713 "GNS REST plugin is finished\n");
714 return NULL;
715}
716
717/* end of plugin_rest_gns.c */
diff --git a/src/gnsrecord/Makefile.am b/src/gnsrecord/Makefile.am
index 47d83169f..f840a31a4 100644
--- a/src/gnsrecord/Makefile.am
+++ b/src/gnsrecord/Makefile.am
@@ -39,7 +39,6 @@ libgnunetgnsrecord_la_SOURCES = \
39 gnsrecord_misc.c 39 gnsrecord_misc.c
40libgnunetgnsrecord_la_LIBADD = \ 40libgnunetgnsrecord_la_LIBADD = \
41 $(top_builddir)/src/util/libgnunetutil.la \ 41 $(top_builddir)/src/util/libgnunetutil.la \
42 -ljansson \
43 $(GN_LIBINTL) 42 $(GN_LIBINTL)
44libgnunetgnsrecord_la_LDFLAGS = \ 43libgnunetgnsrecord_la_LDFLAGS = \
45 $(GN_LIB_LDFLAGS) $(WINFLAGS) \ 44 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
diff --git a/src/gnsrecord/gnsrecord.c b/src/gnsrecord/gnsrecord.c
index 30a0ffa83..b80d86073 100644
--- a/src/gnsrecord/gnsrecord.c
+++ b/src/gnsrecord/gnsrecord.c
@@ -247,130 +247,4 @@ GNUNET_GNSRECORD_number_to_typename (uint32_t type)
247 return NULL; 247 return NULL;
248} 248}
249 249
250/**
251 * Parse given JSON object to gns record
252 *
253 * @param cls closure, NULL
254 * @param root the json object representing data
255 * @param spec where to write the data
256 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
257 */
258static int
259parse_gnsrecordobject (void *cls,
260 json_t *root,
261 struct GNUNET_JSON_Specification *spec)
262{
263 struct GNUNET_GNSRECORD_Data *gnsrecord_object;
264 struct GNUNET_TIME_Absolute abs_expiration_time;
265 int unpack_state=0;
266 const char *data;
267 const char *expiration_date;
268 const char *record_type;
269 const char *dummy_value;
270 int flag;
271 void *rdata;
272 size_t rdata_size;
273
274 if(!json_is_object(root))
275 {
276 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
277 "Error json is not array nor object!\n");
278 return GNUNET_SYSERR;
279 }
280 //interpret single gns record
281 unpack_state = json_unpack(root,
282 "{s:s, s:s, s:s, s?:i, s:s!}",
283 "value", &data,
284 "type", &record_type,
285 "expiration_time", &expiration_date,
286 "flag", &flag,
287 "label", &dummy_value);
288 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
289 "{value:%s, type:%s, expire:%s, flag:%i}",
290 data,
291 record_type,
292 expiration_date,
293 flag);
294 if (GNUNET_SYSERR == unpack_state)
295 {
296 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
297 "Error json object has a wrong format!\n");
298 return GNUNET_SYSERR;
299 }
300 //TODO test
301 gnsrecord_object = GNUNET_new (struct GNUNET_GNSRECORD_Data);
302 gnsrecord_object->record_type = GNUNET_GNSRECORD_typename_to_number(record_type);
303 if (GNUNET_OK
304 != GNUNET_GNSRECORD_string_to_value (gnsrecord_object->record_type,
305 data, &rdata,
306 &rdata_size))
307 {
308 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,"Value invalid for record type");
309 return GNUNET_SYSERR;
310 }
311 gnsrecord_object->data = rdata;
312 gnsrecord_object->data_size = rdata_size;
313
314 if (0 == strcmp (expiration_date, "never"))
315 {
316 gnsrecord_object->expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
317 }
318 else if (GNUNET_OK
319 == GNUNET_STRINGS_fancy_time_to_absolute (expiration_date,
320 &abs_expiration_time))
321 {
322 gnsrecord_object->expiration_time = abs_expiration_time.abs_value_us;
323 }
324 else
325 {
326 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Value invalid for record type");
327 return GNUNET_SYSERR;
328 }
329 gnsrecord_object->flags = (enum GNUNET_GNSRECORD_Flags)flag;
330 *(struct GNUNET_GNSRECORD_Data **) spec->ptr = gnsrecord_object;
331 return GNUNET_OK;
332}
333
334/**
335 * Cleanup data left from parsing RSA public key.
336 *
337 * @param cls closure, NULL
338 * @param[out] spec where to free the data
339 */
340static void
341clean_gnsrecordobject (void *cls, struct GNUNET_JSON_Specification *spec)
342{
343 struct GNUNET_GNSRECORD_Data **gnsrecord_object;
344 gnsrecord_object = (struct GNUNET_GNSRECORD_Data **) spec->ptr;
345 if (NULL != *gnsrecord_object)
346 {
347 if (NULL != (*gnsrecord_object)->data)
348 GNUNET_free((char*)(*gnsrecord_object)->data);
349 GNUNET_free(*gnsrecord_object);
350 *gnsrecord_object = NULL;
351 }
352}
353
354/**
355 * JSON Specification for GNS Records.
356 *
357 * @param gnsrecord_object struct of GNUNET_GNSRECORD_Data to fill
358 * @return JSON Specification
359 */
360struct GNUNET_JSON_Specification
361GNUNET_JSON_spec_gnsrecord_data (struct GNUNET_GNSRECORD_Data **gnsrecord_object)
362{
363 struct GNUNET_JSON_Specification ret = {
364 .parser = &parse_gnsrecordobject,
365 .cleaner = &clean_gnsrecordobject,
366 .cls = NULL,
367 .field = NULL,
368 .ptr = gnsrecord_object,
369 .ptr_size = 0,
370 .size_ptr = NULL
371 };
372 *gnsrecord_object = NULL;
373 return ret;
374}
375
376/* end of gnsrecord.c */ 250/* end of gnsrecord.c */
diff --git a/src/identity/plugin_rest_identity.c b/src/identity/plugin_rest_identity.c
index 59dad66c7..49fa9f0fb 100644
--- a/src/identity/plugin_rest_identity.c
+++ b/src/identity/plugin_rest_identity.c
@@ -42,7 +42,7 @@
42/** 42/**
43 * Error messages 43 * Error messages
44 */ 44 */
45#define GNUNET_REST_ERROR_UNKNOWN "Unknown Error" 45#define GNUNET_REST_IDENTITY_ERROR_UNKNOWN "Unknown Error"
46#define GNUNET_REST_ERROR_RESOURCE_INVALID "Resource location invalid" 46#define GNUNET_REST_ERROR_RESOURCE_INVALID "Resource location invalid"
47#define GNUNET_REST_ERROR_NO_DATA "No data" 47#define GNUNET_REST_ERROR_NO_DATA "No data"
48#define GNUNET_REST_ERROR_DATA_INVALID "Data invalid" 48#define GNUNET_REST_ERROR_DATA_INVALID "Data invalid"
@@ -251,7 +251,7 @@ do_error (void *cls)
251 char *response; 251 char *response;
252 252
253 if (NULL == handle->emsg) 253 if (NULL == handle->emsg)
254 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_UNKNOWN); 254 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_ERROR_UNKNOWN);
255 255
256 json_object_set_new(json_error,"error", json_string(handle->emsg)); 256 json_object_set_new(json_error,"error", json_string(handle->emsg));
257 257
diff --git a/src/include/gnunet_gnsrecord_lib.h b/src/include/gnunet_gnsrecord_lib.h
index 2eaa304de..20846238b 100644
--- a/src/include/gnunet_gnsrecord_lib.h
+++ b/src/include/gnunet_gnsrecord_lib.h
@@ -447,14 +447,6 @@ GNUNET_GNSRECORD_records_deserialize (size_t len,
447 unsigned int rd_count, 447 unsigned int rd_count,
448 struct GNUNET_GNSRECORD_Data *dest); 448 struct GNUNET_GNSRECORD_Data *dest);
449 449
450/**
451 * JSON Specification for GNS Records.
452 *
453 * @param gnsrecord_object struct of GNUNET_GNSRECORD_Data to fill
454 * @return JSON Specification
455 */
456struct GNUNET_JSON_Specification
457GNUNET_JSON_spec_gnsrecord_data (struct GNUNET_GNSRECORD_Data **gnsrecord_object);
458 450
459/* ******* general APIs relating to blocks, records and labels ******** */ 451/* ******* general APIs relating to blocks, records and labels ******** */
460 452
diff --git a/src/include/gnunet_json_lib.h b/src/include/gnunet_json_lib.h
index 4855f21b4..781d5698b 100644
--- a/src/include/gnunet_json_lib.h
+++ b/src/include/gnunet_json_lib.h
@@ -26,6 +26,7 @@
26#define GNUNET_JSON_LIB_H 26#define GNUNET_JSON_LIB_H
27 27
28#include "gnunet_util_lib.h" 28#include "gnunet_util_lib.h"
29#include "gnunet_gnsrecord_lib.h"
29#include <jansson.h> 30#include <jansson.h>
30 31
31 32
@@ -318,6 +319,17 @@ GNUNET_JSON_spec_rsa_signature (const char *name,
318 struct GNUNET_CRYPTO_RsaSignature **sig); 319 struct GNUNET_CRYPTO_RsaSignature **sig);
319 320
320 321
322
323/**
324 * JSON Specification for GNS Records.
325 *
326 * @param gnsrecord_object struct of GNUNET_GNSRECORD_Data to fill
327 * @return JSON Specification
328 */
329struct GNUNET_JSON_Specification
330GNUNET_JSON_spec_gnsrecord_data (struct GNUNET_GNSRECORD_Data **gnsrecord_object);
331
332
321/* ****************** Generic generator interface ******************* */ 333/* ****************** Generic generator interface ******************* */
322 334
323 335
@@ -393,6 +405,16 @@ GNUNET_JSON_from_rsa_public_key (const struct GNUNET_CRYPTO_RsaPublicKey *pk);
393json_t * 405json_t *
394GNUNET_JSON_from_rsa_signature (const struct GNUNET_CRYPTO_RsaSignature *sig); 406GNUNET_JSON_from_rsa_signature (const struct GNUNET_CRYPTO_RsaSignature *sig);
395 407
408/**
409 * Convert Gns record to JSON.
410 *
411 * @param rname name of record
412 * @param rd record data
413 * @return corresponding JSON encoding
414 */
415json_t *
416GNUNET_JSON_from_gns_record (const char* rname,
417 const struct GNUNET_GNSRECORD_Data *rd);
396 418
397/* ******************* Helpers for MHD upload handling ******************* */ 419/* ******************* Helpers for MHD upload handling ******************* */
398 420
diff --git a/src/json/Makefile.am b/src/json/Makefile.am
index 16c0450d9..04f27fec7 100644
--- a/src/json/Makefile.am
+++ b/src/json/Makefile.am
@@ -16,7 +16,8 @@ libgnunetjson_la_SOURCES = \
16 json.c \ 16 json.c \
17 json_mhd.c \ 17 json_mhd.c \
18 json_generator.c \ 18 json_generator.c \
19 json_helper.c 19 json_helper.c \
20 json_gnsrecord.c
20libgnunetjson_la_LIBADD = \ 21libgnunetjson_la_LIBADD = \
21 $(top_builddir)/src/util/libgnunetutil.la \ 22 $(top_builddir)/src/util/libgnunetutil.la \
22 -ljansson \ 23 -ljansson \
diff --git a/src/json/json_generator.c b/src/json/json_generator.c
index dd6df4f74..7b24a3c12 100644
--- a/src/json/json_generator.c
+++ b/src/json/json_generator.c
@@ -157,5 +157,40 @@ GNUNET_JSON_from_rsa_signature (const struct GNUNET_CRYPTO_RsaSignature *sig)
157 return ret; 157 return ret;
158} 158}
159 159
160/**
161 * Convert Gns record to JSON.
162 *
163 * @param rname name of record
164 * @param rd record data
165 * @return corresponding JSON encoding
166 */
167json_t *
168GNUNET_JSON_from_gns_record (const char* rname,
169 const struct GNUNET_GNSRECORD_Data *rd)
170{
171 struct GNUNET_TIME_Absolute expiration_time;
172 const char *expiration_time_str;
173 const char *record_type_str;
174 char *value_str;
175 json_t *ret;
176 int flags;
177
178 value_str = GNUNET_GNSRECORD_value_to_string(rd->record_type,rd->data,rd->data_size);
179 expiration_time = GNUNET_GNSRECORD_record_get_expiration_time(1, rd);
180 expiration_time_str = GNUNET_STRINGS_absolute_time_to_string(expiration_time);
181 flags = (int)rd->flags; //maybe necessary
182 record_type_str = GNUNET_GNSRECORD_number_to_typename(rd->record_type);
183
184 // ? for possible NULL values
185 ret = json_pack("{s:s?,s:s?,s:s?,s:i,s:s?}",
186 "value", value_str,
187 "type", record_type_str,
188 "expiration_time", expiration_time_str,
189 "flag", flags,
190 "label", rname);
191 GNUNET_free_non_null(value_str);
192 return ret;
193}
194
160 195
161/* End of json/json_generator.c */ 196/* End of json/json_generator.c */
diff --git a/src/json/json_gnsrecord.c b/src/json/json_gnsrecord.c
new file mode 100644
index 000000000..48b78f38b
--- /dev/null
+++ b/src/json/json_gnsrecord.c
@@ -0,0 +1,163 @@
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
19/**
20 * @file json/json_gnsrecord.c
21 * @brief JSON handling of GNS record data
22 * @author Philippe Buschmann
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26#include "gnunet_gnsrecord_lib.h"
27#include "gnunet_json_lib.h"
28
29#define GNUNET_JSON_GNSRECORD_VALUE "value"
30#define GNUNET_JSON_GNSRECORD_TYPE "type"
31#define GNUNET_JSON_GNSRECORD_EXPIRATION_TIME "expiration_time"
32#define GNUNET_JSON_GNSRECORD_FLAG "flag"
33#define GNUNET_JSON_GNSRECORD_LABEL "label"
34#define GNUNET_JSON_GNSRECORD_NEVER "never"
35
36
37/**
38 * Parse given JSON object to gns record
39 *
40 * @param cls closure, NULL
41 * @param root the json object representing data
42 * @param spec where to write the data
43 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
44 */
45static int
46parse_gnsrecordobject (void *cls,
47 json_t *root,
48 struct GNUNET_JSON_Specification *spec)
49{
50 struct GNUNET_GNSRECORD_Data *gnsrecord_object;
51 struct GNUNET_TIME_Absolute abs_expiration_time;
52 int unpack_state=0;
53 const char *value;
54 const char *expiration_time;
55 const char *record_type;
56 const char *label;
57 int flag;
58 void *rdata;
59 size_t rdata_size;
60
61 GNUNET_assert(NULL != root);
62 if(!json_is_object(root))
63 {
64 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
65 "Error json is not array nor object!\n");
66 return GNUNET_SYSERR;
67 }
68 //interpret single gns record
69 unpack_state = json_unpack(root,
70 "{s:s, s:s, s:s, s?:i, s:s!}",
71 GNUNET_JSON_GNSRECORD_VALUE, &value,
72 GNUNET_JSON_GNSRECORD_TYPE, &record_type,
73 GNUNET_JSON_GNSRECORD_EXPIRATION_TIME, &expiration_time,
74 GNUNET_JSON_GNSRECORD_FLAG, &flag,
75 GNUNET_JSON_GNSRECORD_LABEL, &label);
76 if (GNUNET_SYSERR == unpack_state)
77 {
78 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
79 "Error json object has a wrong format!\n");
80 return GNUNET_SYSERR;
81 }
82 gnsrecord_object = GNUNET_new (struct GNUNET_GNSRECORD_Data);
83 gnsrecord_object->record_type = GNUNET_GNSRECORD_typename_to_number(record_type);
84 if (UINT32_MAX == gnsrecord_object->record_type)
85 {
86 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,"Unsupported type");
87 return GNUNET_SYSERR;
88 }
89 if (GNUNET_OK
90 != GNUNET_GNSRECORD_string_to_value (gnsrecord_object->record_type,
91 value,
92 &rdata,
93 &rdata_size))
94 {
95 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,"Value invalid for record type");
96 return GNUNET_SYSERR;
97 }
98
99 gnsrecord_object->data = rdata;
100 gnsrecord_object->data_size = rdata_size;
101
102 if (0 == strcmp (expiration_time, GNUNET_JSON_GNSRECORD_NEVER))
103 {
104 gnsrecord_object->expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
105 }
106 else if (GNUNET_OK
107 == GNUNET_STRINGS_fancy_time_to_absolute (expiration_time,
108 &abs_expiration_time))
109 {
110 gnsrecord_object->expiration_time = abs_expiration_time.abs_value_us;
111 }
112 else
113 {
114 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Value invalid for expiration time");
115 return GNUNET_SYSERR;
116 }
117 gnsrecord_object->flags = (enum GNUNET_GNSRECORD_Flags)flag;
118 *(struct GNUNET_GNSRECORD_Data **) spec->ptr = gnsrecord_object;
119 return GNUNET_OK;
120}
121
122/**
123 * Cleanup data left from parsing RSA public key.
124 *
125 * @param cls closure, NULL
126 * @param[out] spec where to free the data
127 */
128static void
129clean_gnsrecordobject (void *cls, struct GNUNET_JSON_Specification *spec)
130{
131 struct GNUNET_GNSRECORD_Data **gnsrecord_object;
132 gnsrecord_object = (struct GNUNET_GNSRECORD_Data **) spec->ptr;
133 if (NULL != *gnsrecord_object)
134 {
135 if (NULL != (*gnsrecord_object)->data)
136 GNUNET_free((char*)(*gnsrecord_object)->data);
137
138 GNUNET_free(*gnsrecord_object);
139 *gnsrecord_object = NULL;
140 }
141}
142
143/**
144 * JSON Specification for GNS Records.
145 *
146 * @param gnsrecord_object struct of GNUNET_GNSRECORD_Data to fill
147 * @return JSON Specification
148 */
149struct GNUNET_JSON_Specification
150GNUNET_JSON_spec_gnsrecord_data (struct GNUNET_GNSRECORD_Data **gnsrecord_object)
151{
152 struct GNUNET_JSON_Specification ret = {
153 .parser = &parse_gnsrecordobject,
154 .cleaner = &clean_gnsrecordobject,
155 .cls = NULL,
156 .field = NULL,
157 .ptr = gnsrecord_object,
158 .ptr_size = 0,
159 .size_ptr = NULL
160 };
161 *gnsrecord_object = NULL;
162 return ret;
163}
diff --git a/src/namestore/plugin_rest_namestore.c b/src/namestore/plugin_rest_namestore.c
index afe010b79..6924c53a4 100644
--- a/src/namestore/plugin_rest_namestore.c
+++ b/src/namestore/plugin_rest_namestore.c
@@ -36,11 +36,7 @@
36 36
37#define GNUNET_REST_SUBSYSTEM_NAMESTORE "namestore" 37#define GNUNET_REST_SUBSYSTEM_NAMESTORE "namestore"
38 38
39#define GNUNET_REST_JSON_NAMESTORE_RECORD_TYPE "record_type" 39#define GNUNET_REST_NAMESTORE_ERROR_UNKNOWN "Unknown Error"
40#define GNUNET_REST_JSON_NAMESTORE_VALUE "value"
41#define GNUNET_REST_JSON_NAMESTORE_EXPIRATION "expiration"
42#define GNUNET_REST_JSON_NAMESTORE_EXPIRED "expired"
43#define GNUNET_REST_ERROR_UNKNOWN "Unknown Error"
44 40
45#define GNUNET_REST_NAMESTORE_RD_COUNT 1 41#define GNUNET_REST_NAMESTORE_RD_COUNT 1
46 42
@@ -194,8 +190,6 @@ static void
194cleanup_handle (void *cls) 190cleanup_handle (void *cls)
195{ 191{
196 struct RequestHandle *handle = cls; 192 struct RequestHandle *handle = cls;
197 size_t index;
198 json_t *json_ego;
199 193
200 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 194 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
201 "Cleaning up\n"); 195 "Cleaning up\n");
@@ -239,10 +233,6 @@ cleanup_handle (void *cls)
239 233
240 if(NULL != handle->resp_object) 234 if(NULL != handle->resp_object)
241 { 235 {
242 json_array_foreach(handle->resp_object, index, json_ego )
243 {
244 json_decref (json_ego);
245 }
246 json_decref(handle->resp_object); 236 json_decref(handle->resp_object);
247 } 237 }
248 238
@@ -264,7 +254,7 @@ do_error (void *cls)
264 char *response; 254 char *response;
265 255
266 if (NULL == handle->emsg) 256 if (NULL == handle->emsg)
267 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_UNKNOWN); 257 handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_ERROR_UNKNOWN);
268 258
269 json_object_set_new(json_error,"error", json_string(handle->emsg)); 259 json_object_set_new(json_error,"error", json_string(handle->emsg));
270 260
@@ -286,66 +276,10 @@ namestore_iteration_error (void *cls)
286{ 276{
287 struct RequestHandle *handle = cls; 277 struct RequestHandle *handle = cls;
288 struct MHD_Response *resp = GNUNET_REST_create_response (NULL); 278 struct MHD_Response *resp = GNUNET_REST_create_response (NULL);
289 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; 279 handle->proc (handle->proc_cls, resp, MHD_HTTP_INTERNAL_SERVER_ERROR);
290 handle->proc (handle->proc_cls, resp, handle->response_code);
291 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); 280 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
292} 281}
293 282
294/**
295 * Create json representation of a GNSRECORD
296 *
297 * @param rd the GNSRECORD_Data
298 */
299static json_t *
300gnsrecord_to_json (const struct GNUNET_GNSRECORD_Data *rd)
301{
302 const char *typename;
303 char *string_val;
304 const char *exp_str;
305 json_t *record_obj;
306
307 typename = GNUNET_GNSRECORD_number_to_typename (rd->record_type);
308 string_val = GNUNET_GNSRECORD_value_to_string (rd->record_type,
309 rd->data,
310 rd->data_size);
311
312 if (NULL == string_val)
313 {
314 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
315 "Record of type %d malformed, skipping\n",
316 (int) rd->record_type);
317 return NULL;
318 }
319 record_obj = json_object();
320 json_object_set_new (record_obj,
321 GNUNET_REST_JSON_NAMESTORE_RECORD_TYPE,
322 json_string (typename));
323 json_object_set_new (record_obj,
324 GNUNET_REST_JSON_NAMESTORE_VALUE,
325 json_string (string_val));
326 //GNUNET_free (string_val);
327
328 if (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION & rd->flags)
329 {
330 struct GNUNET_TIME_Relative time_rel;
331 time_rel.rel_value_us = rd->expiration_time;
332 exp_str = GNUNET_STRINGS_relative_time_to_string (time_rel, 1);
333 }
334 else
335 {
336 struct GNUNET_TIME_Absolute time_abs;
337 time_abs.abs_value_us = rd->expiration_time;
338 exp_str = GNUNET_STRINGS_absolute_time_to_string (time_abs);
339 }
340 json_object_set_new (record_obj,
341 GNUNET_REST_JSON_NAMESTORE_EXPIRATION,
342 json_string (exp_str));
343 json_object_set_new (record_obj, "expired",
344 json_boolean (GNUNET_YES == GNUNET_GNSRECORD_is_expired (rd)));
345 return record_obj;
346}
347
348
349static void 283static void
350create_finished (void *cls, int32_t success, const char *emsg) 284create_finished (void *cls, int32_t success, const char *emsg)
351{ 285{
@@ -364,6 +298,29 @@ create_finished (void *cls, int32_t success, const char *emsg)
364 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle); 298 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
365} 299}
366 300
301static void
302del_finished (void *cls, int32_t success, const char *emsg)
303{
304 struct RequestHandle *handle = cls;
305
306 handle->add_qe = NULL;
307 if (GNUNET_NO == success)
308 {
309 handle->emsg = GNUNET_strdup("Deleting record failed. Record does not exist");
310 GNUNET_SCHEDULER_add_now (&do_error, handle);
311 return;
312 }
313 if (GNUNET_SYSERR == success)
314 {
315 handle->emsg = GNUNET_strdup("Deleting record failed");
316 GNUNET_SCHEDULER_add_now (&do_error, handle);
317 return;
318 }
319 handle->proc (handle->proc_cls,
320 GNUNET_REST_create_response (NULL),
321 MHD_HTTP_NO_CONTENT);
322 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
323}
367/** 324/**
368 * Iteration over all results finished, build final 325 * Iteration over all results finished, build final
369 * response. 326 * response.
@@ -379,10 +336,8 @@ namestore_list_finished (void *cls)
379 336
380 handle->list_it = NULL; 337 handle->list_it = NULL;
381 338
382 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "HEY\n");
383 if (NULL == handle->resp_object) 339 if (NULL == handle->resp_object)
384 { 340 {
385 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "OH\n");
386 GNUNET_SCHEDULER_add_now (&do_error, handle); 341 GNUNET_SCHEDULER_add_now (&do_error, handle);
387 return; 342 return;
388 } 343 }
@@ -415,9 +370,6 @@ namestore_list_iteration (void *cls,
415 if (NULL == handle->resp_object) 370 if (NULL == handle->resp_object)
416 handle->resp_object = json_array(); 371 handle->resp_object = json_array();
417 372
418 char *result_str = json_dumps (handle->resp_object, 0);
419 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "%s\n", result_str);
420 GNUNET_free(result_str);
421 /*if ( (NULL != handle->ego_entry->identifier) && 373 /*if ( (NULL != handle->ego_entry->identifier) &&
422 (0 != strcmp (handle->ego_entry->identifier, 374 (0 != strcmp (handle->ego_entry->identifier,
423 rname)) ) 375 rname)) )
@@ -435,13 +387,12 @@ namestore_list_iteration (void *cls,
435 (0 != strcmp (rname, GNUNET_GNS_EMPTY_LABEL_AT)) ) 387 (0 != strcmp (rname, GNUNET_GNS_EMPTY_LABEL_AT)) )
436 continue; 388 continue;
437 389
438 record_obj = gnsrecord_to_json (&rd[i]); 390 record_obj = GNUNET_JSON_from_gns_record(rname,rd);
439 391
440 if(NULL == record_obj) 392 if(NULL == record_obj)
441 continue; 393 continue;
442 394
443 json_array_append (handle->resp_object, 395 json_array_append (handle->resp_object, record_obj);
444 record_obj);
445 json_decref (record_obj); 396 json_decref (record_obj);
446 } 397 }
447 398
@@ -477,73 +428,7 @@ namestore_get (struct GNUNET_REST_RequestHandle *con_handle,
477 &namestore_list_finished, 428 &namestore_list_finished,
478 handle); 429 handle);
479} 430}
480/*
481 431
482//TODO filter input
483static int
484json_to_gnsrecord (struct RequestHandle *handle)
485{
486 struct GNUNET_TIME_Relative etime_rel;
487 struct GNUNET_TIME_Absolute etime_abs;
488 void *rdata;
489 size_t rdata_size;
490
491 handle->rd = GNUNET_new_array(GNUNET_REST_NAMESTORE_RD_COUNT,
492 struct GNUNET_GNSRECORD_Data);
493 memset (handle->rd, 0, sizeof(struct GNUNET_GNSRECORD_Data));
494 handle->rd->record_type = GNUNET_GNSRECORD_typename_to_number (
495 handle->json_data->type);
496 if (UINT32_MAX == (*handle->rd).record_type)
497 {
498 handle->emsg = GNUNET_strdup("Unsupported type");
499 return GNUNET_SYSERR;
500 }
501 if (GNUNET_OK
502 != GNUNET_GNSRECORD_string_to_value ((*handle->rd).record_type,
503 handle->json_data->value, &rdata,
504 &rdata_size))
505 {
506 handle->emsg = GNUNET_strdup("Value invalid for record type");
507 return GNUNET_SYSERR;
508 }
509 (*handle->rd).data = rdata;
510 (*handle->rd).data_size = rdata_size;
511 //TODO other flags
512 if (0 == handle->json_data->is_public)
513 {
514 handle->rd->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
515 }
516 /**TODO
517 * if (1 == handle->is_shadow)
518 rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
519 if (1 != handle->is_public)
520 rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
521 *
522 if (0 == strcmp (handle->json_data->expiration_time, "never"))
523 {
524 (*handle->rd).expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
525 }
526 else if (GNUNET_OK
527 == GNUNET_STRINGS_fancy_time_to_relative (
528 handle->json_data->expiration_time, &etime_rel))
529 {
530 (*handle->rd).expiration_time = etime_rel.rel_value_us;
531 (*handle->rd).flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
532 }
533 else if (GNUNET_OK
534 == GNUNET_STRINGS_fancy_time_to_absolute (
535 handle->json_data->expiration_time, &etime_abs))
536 {
537 (*handle->rd).expiration_time = etime_abs.abs_value_us;
538 }
539 else
540 {
541 handle->emsg = GNUNET_strdup("Value invalid for record type");
542 return GNUNET_SYSERR;
543 }
544 return GNUNET_OK;
545}
546*/
547 432
548/** 433/**
549 * We're storing a new record; this requires 434 * We're storing a new record; this requires
@@ -564,12 +449,11 @@ create_new_record_cont (void *cls,
564{ 449{
565 struct RequestHandle *handle = cls; 450 struct RequestHandle *handle = cls;
566 451
567
568 handle->add_qe = NULL; 452 handle->add_qe = NULL;
569 if (0 != strcmp (rec_name, handle->label_name)) 453 if (0 != strcmp (rec_name, handle->label_name))
570 { 454 {
571 GNUNET_break (0); 455 GNUNET_break (0);
572 do_error (handle); 456 GNUNET_SCHEDULER_add_now (&do_error, handle);
573 return; 457 return;
574 } 458 }
575 459
@@ -656,6 +540,31 @@ namestore_add (struct GNUNET_REST_RequestHandle *con_handle,
656} 540}
657 541
658 542
543static void
544del_cont (void *cls,
545 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
546 const char *label,
547 unsigned int rd_count,
548 const struct GNUNET_GNSRECORD_Data *rd)
549{
550 struct RequestHandle *handle = cls;
551
552 handle->add_qe = NULL;
553 if (0 == rd_count)
554 {
555 handle->emsg = GNUNET_strdup("Record not found");
556 GNUNET_SCHEDULER_add_now (&do_error, handle);
557 return;
558 }
559
560 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
561 &handle->zone_pkey,
562 handle->label_name,
563 0, NULL,
564 &del_finished,
565 handle);
566}
567
659/** 568/**
660 * Handle namestore DELETE request 569 * Handle namestore DELETE request
661 * 570 *
@@ -669,12 +578,28 @@ namestore_delete (struct GNUNET_REST_RequestHandle *con_handle,
669 void *cls) 578 void *cls)
670{ 579{
671 struct RequestHandle *handle = cls; 580 struct RequestHandle *handle = cls;
581 struct GNUNET_HashCode key;
582
583 GNUNET_CRYPTO_hash ("label", strlen ("label"), &key);
584 if ( GNUNET_NO
585 == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
586 &key))
587 {
588 handle->emsg = GNUNET_strdup("Missing name");
589 GNUNET_SCHEDULER_add_now (&do_error, handle);
590 return;
591 }
592 handle->label_name = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map,
593 &key);
672 594
673 //TODO add behaviour and response 595 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
674 596 &handle->zone_pkey,
675 handle->emsg = GNUNET_strdup ("Not implemented yet"); 597 handle->label_name,
676 GNUNET_SCHEDULER_add_now (&do_error, handle); 598 &do_error,
677 return; 599 handle,
600 &del_cont,
601 handle);
602
678} 603}
679 604
680 605
diff --git a/src/namestore/plugin_rest_namestore2.c b/src/namestore/plugin_rest_namestore2.c
deleted file mode 100644
index ec44046e0..000000000
--- a/src/namestore/plugin_rest_namestore2.c
+++ /dev/null
@@ -1,1229 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 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/**
19 * @author Martin Schanzenbach
20 * @file namestore/plugin_rest_namestore.c
21 * @brief GNUnet Namestore REST plugin
22 *
23 */
24
25#include "platform.h"
26#include "gnunet_rest_plugin.h"
27#include "gnunet_gns_service.h"
28#include "gnunet_namestore_service.h"
29#include "gnunet_identity_service.h"
30#include "gnunet_rest_lib.h"
31#include "gnunet_jsonapi_lib.h"
32#include "gnunet_jsonapi_util.h"
33#include "microhttpd.h"
34#include <jansson.h>
35
36#define GNUNET_REST_API_NS_NAMESTORE "/names"
37
38#define GNUNET_REST_API_NS_NAMESTORE_ZKEY "/names/zkey"
39
40#define GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO "record"
41
42#define GNUNET_REST_JSONAPI_NAMESTORE_NAME "name"
43
44#define GNUNET_REST_JSONAPI_NAMESTORE_REVINFO "revinfo"
45
46#define GNUNET_REST_JSONAPI_NAMESTORE_RECORD GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO
47
48#define GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE "record_type"
49
50#define GNUNET_REST_JSONAPI_NAMESTORE_VALUE "value"
51
52#define GNUNET_REST_JSONAPI_NAMESTORE_PUBLIC "public"
53
54#define GNUNET_REST_JSONAPI_NAMESTORE_SHADOW "shadow"
55
56#define GNUNET_REST_JSONAPI_NAMESTORE_PKEY "pkey"
57
58#define GNUNET_REST_JSONAPI_NAMESTORE_ZKEY "zkey"
59
60#define GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION "expiration"
61
62#define GNUNET_REST_JSONAPI_NAMESTORE_EGO "ego"
63
64/**
65 * @brief struct returned by the initialization function of the plugin
66 */
67struct Plugin
68{
69 const struct GNUNET_CONFIGURATION_Handle *cfg;
70};
71
72
73/**
74 * HTTP methods allows for this plugin
75 */
76static char* allow_methods;
77
78const struct GNUNET_CONFIGURATION_Handle *cfg;
79
80struct RecordEntry
81{
82 /**
83 * DLL
84 */
85 struct RecordEntry *next;
86
87 /**
88 * DLL
89 */
90 struct RecordEntry *prev;
91
92};
93
94struct RequestHandle
95{
96 /**
97 * Ego list
98 */
99 struct RecordEntry *record_head;
100
101 /**
102 * Ego list
103 */
104 struct record_entry *record_tail;
105
106 /**
107 * JSON response object
108 */
109 struct GNUNET_JSONAPI_Document *resp_object;
110
111 /**
112 * Rest connection
113 */
114 struct GNUNET_REST_RequestHandle *rest_handle;
115
116 /**
117 * Handle to GNS service.
118 */
119 struct GNUNET_IDENTITY_Handle *identity_handle;
120
121 /**
122 * Handle to NAMESTORE
123 */
124 struct GNUNET_NAMESTORE_Handle *ns_handle;
125
126 /**
127 * Handle to NAMESTORE it
128 */
129 struct GNUNET_NAMESTORE_ZoneIterator *list_it;
130
131 /**
132 * Private key for the zone
133 */
134 struct GNUNET_CRYPTO_EcdsaPrivateKey zone_pkey;
135
136 /**
137 * Handle to identity lookup
138 */
139 struct GNUNET_IDENTITY_EgoLookup *ego_lookup;
140
141 /**
142 * Default Ego operation
143 */
144 struct GNUNET_IDENTITY_Operation *get_default;
145
146 /**
147 * Name of the ego
148 */
149 char *ego_name;
150
151 /**
152 * Record is public
153 */
154 int is_public;
155
156 /**
157 * Shadow record
158 */
159 int is_shadow;
160
161 /**
162 * Name of the record to modify
163 */
164 char *name;
165
166 /**
167 * Value of the record
168 */
169 char *value;
170
171 /**
172 * Zkey string
173 */
174 const char* zkey_str;
175
176 /**
177 * record type
178 */
179 uint32_t type;
180
181 /**
182 * Records to store
183 */
184 struct GNUNET_GNSRECORD_Data *rd;
185
186 /**
187 * record count
188 */
189 unsigned int rd_count;
190
191 /**
192 * NAMESTORE Operation
193 */
194 struct GNUNET_NAMESTORE_QueueEntry *add_qe;
195
196 /**
197 * NAMESTORE Operation
198 */
199 struct GNUNET_NAMESTORE_QueueEntry *reverse_qe;
200
201 /**
202 * Desired timeout for the lookup (default is no timeout).
203 */
204 struct GNUNET_TIME_Relative timeout;
205
206 /**
207 * ID of a task associated with the resolution process.
208 */
209 struct GNUNET_SCHEDULER_Task * timeout_task;
210
211 /**
212 * The plugin result processor
213 */
214 GNUNET_REST_ResultProcessor proc;
215
216 /**
217 * The closure of the result processor
218 */
219 void *proc_cls;
220
221 /**
222 * The url
223 */
224 char *url;
225
226 /**
227 * Cfg
228 */
229 const struct GNUNET_CONFIGURATION_Handle *cfg;
230
231 /**
232 * HTTP response code
233 */
234 int response_code;
235
236};
237
238
239/**
240 * Cleanup lookup handle
241 *
242 * @param handle Handle to clean up
243 */
244static void
245cleanup_handle (struct RequestHandle *handle)
246{
247 struct RecordEntry *record_entry;
248 struct RecordEntry *record_tmp;
249
250 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
251 "Cleaning up\n");
252 if (NULL != handle->resp_object)
253 GNUNET_JSONAPI_document_delete (handle->resp_object);
254 if (NULL != handle->name)
255 GNUNET_free (handle->name);
256 if (NULL != handle->timeout_task)
257 GNUNET_SCHEDULER_cancel (handle->timeout_task);
258 if (NULL != handle->ego_lookup)
259 GNUNET_IDENTITY_ego_lookup_cancel (handle->ego_lookup);
260 if (NULL != handle->get_default)
261 GNUNET_IDENTITY_cancel (handle->get_default);
262 if (NULL != handle->list_it)
263 GNUNET_NAMESTORE_zone_iteration_stop (handle->list_it);
264 if (NULL != handle->add_qe)
265 GNUNET_NAMESTORE_cancel (handle->add_qe);
266 if (NULL != handle->identity_handle)
267 GNUNET_IDENTITY_disconnect (handle->identity_handle);
268 if (NULL != handle->ns_handle)
269 GNUNET_NAMESTORE_disconnect (handle->ns_handle);
270 if (NULL != handle->url)
271 GNUNET_free (handle->url);
272 if (NULL != handle->value)
273 GNUNET_free (handle->value);
274 if (NULL != handle->rd)
275 {
276 for (unsigned int i = 0; i < handle->rd_count; i++)
277 {
278 if (NULL != handle->rd[i].data)
279 GNUNET_free ((void*)handle->rd[i].data);
280 }
281 GNUNET_free (handle->rd);
282 }
283 if (NULL != handle->ego_name)
284 GNUNET_free (handle->ego_name);
285 for (record_entry = handle->record_head;
286 NULL != record_entry;)
287 {
288 record_tmp = record_entry;
289 record_entry = record_entry->next;
290 GNUNET_free (record_tmp);
291 }
292 GNUNET_free (handle);
293}
294
295
296/**
297 * Create json representation of a GNSRECORD
298 *
299 * @param rd the GNSRECORD_Data
300 */
301static json_t *
302gnsrecord_to_json (const struct GNUNET_GNSRECORD_Data *rd)
303{
304 const char *typename;
305 char *string_val;
306 const char *exp_str;
307 json_t *record_obj;
308
309 typename = GNUNET_GNSRECORD_number_to_typename (rd->record_type);
310 string_val = GNUNET_GNSRECORD_value_to_string (rd->record_type,
311 rd->data,
312 rd->data_size);
313
314 if (NULL == string_val)
315 {
316 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
317 "Record of type %d malformed, skipping\n",
318 (int) rd->record_type);
319 return NULL;
320 }
321 record_obj = json_object();
322 json_object_set_new (record_obj,
323 GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
324 json_string (typename));
325 json_object_set_new (record_obj,
326 GNUNET_REST_JSONAPI_NAMESTORE_VALUE,
327 json_string (string_val));
328 GNUNET_free (string_val);
329
330 if (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION & rd->flags)
331 {
332 struct GNUNET_TIME_Relative time_rel;
333 time_rel.rel_value_us = rd->expiration_time;
334 exp_str = GNUNET_STRINGS_relative_time_to_string (time_rel, 1);
335 }
336 else
337 {
338 struct GNUNET_TIME_Absolute time_abs;
339 time_abs.abs_value_us = rd->expiration_time;
340 exp_str = GNUNET_STRINGS_absolute_time_to_string (time_abs);
341 }
342 json_object_set_new (record_obj, GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION, json_string (exp_str));
343
344 json_object_set_new (record_obj, "expired",
345 json_boolean (GNUNET_YES == GNUNET_GNSRECORD_is_expired (rd)));
346 return record_obj;
347}
348
349
350/**
351 * Task run on error. Generates error response and cleans up.
352 *
353 * @param cls the request to generate an error response for
354 */
355static void
356do_error (void *cls)
357{
358 struct RequestHandle *handle = cls;
359 struct MHD_Response *resp = GNUNET_REST_create_response (NULL);
360
361 handle->proc (handle->proc_cls, resp, handle->response_code);
362 cleanup_handle (handle);
363}
364
365
366/**
367 * Task run on timeout.
368 *
369 * @param cls the request to time out
370 */
371static void
372do_timeout (void *cls)
373{
374 struct RequestHandle *handle = cls;
375
376 handle->timeout_task = NULL;
377 do_error (handle);
378}
379
380
381static void
382cleanup_handle_delayed (void *cls)
383{
384 cleanup_handle (cls);
385}
386
387
388/**
389 * Iteration over all results finished, build final
390 * response.
391 *
392 * @param cls the `struct RequestHandle`
393 */
394static void
395namestore_list_finished (void *cls)
396{
397 struct RequestHandle *handle = cls;
398 char *result;
399 struct MHD_Response *resp;
400
401 handle->list_it = NULL;
402 if (NULL == handle->resp_object)
403 handle->resp_object = GNUNET_JSONAPI_document_new ();
404
405 if (GNUNET_SYSERR ==
406 GNUNET_JSONAPI_document_serialize (handle->resp_object,
407 &result))
408 {
409 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
410 GNUNET_SCHEDULER_add_now (&do_error,
411 handle);
412 return;
413 }
414 resp = GNUNET_REST_create_response (result);
415 handle->proc (handle->proc_cls,
416 resp,
417 MHD_HTTP_OK);
418 GNUNET_free_non_null (result);
419 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed,
420 handle);
421}
422
423
424
425/**
426 * Create a response with requested records
427 *
428 * @param handle the RequestHandle
429 */
430static void
431namestore_list_response (void *cls,
432 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
433 const char *rname,
434 unsigned int rd_len,
435 const struct GNUNET_GNSRECORD_Data *rd)
436{
437 struct RequestHandle *handle = cls;
438 struct GNUNET_JSONAPI_Resource *json_resource;
439 json_t *result_array;
440 json_t *record_obj;
441
442 if (NULL == handle->resp_object)
443 handle->resp_object = GNUNET_JSONAPI_document_new ();
444
445 if ( (NULL != handle->name) &&
446 (0 != strcmp (handle->name,
447 rname)) )
448 {
449 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
450 "%s does not match %s\n",
451 rname,
452 handle->name);
453 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it,
454 1);
455 return;
456 }
457
458 result_array = json_array ();
459 for (unsigned int i=0; i<rd_len; i++)
460 {
461 if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
462 (0 != strcmp (rname, GNUNET_GNS_EMPTY_LABEL_AT)) )
463 continue;
464
465 if ( (rd[i].record_type != handle->type) &&
466 (GNUNET_GNSRECORD_TYPE_ANY != handle->type) )
467 continue;
468 record_obj = gnsrecord_to_json (&rd[i]);
469 json_array_append (result_array,
470 record_obj);
471 json_decref (record_obj);
472 }
473
474 if (0 < json_array_size(result_array))
475 {
476 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO,
477 rname);
478 GNUNET_JSONAPI_resource_add_attr (json_resource,
479 GNUNET_REST_JSONAPI_NAMESTORE_RECORD,
480 result_array);
481 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
482 }
483
484 json_decref (result_array);
485 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it,
486 1);
487}
488
489
490static void
491create_finished (void *cls, int32_t success, const char *emsg)
492{
493 struct RequestHandle *handle = cls;
494 struct MHD_Response *resp;
495
496 handle->add_qe = NULL;
497 if (GNUNET_YES != success)
498 {
499 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
500 "Error storing records%s%s\n",
501 (NULL == emsg) ? "" : ": ",
502 (NULL == emsg) ? "" : emsg);
503 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
504 return;
505 }
506 resp = GNUNET_REST_create_response (NULL);
507 handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
508 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
509}
510
511
512/**
513 * We're storing a new record; this requires
514 * that no record already exists
515 *
516 * @param cls closure, unused
517 * @param zone_key private key of the zone
518 * @param rec_name name that is being mapped (at most 255 characters long)
519 * @param rd_count number of entries in @a rd array
520 * @param rd array of records with data to store
521 */
522static void
523create_new_record_cont (void *cls,
524 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
525 const char *rec_name,
526 unsigned int rd_count,
527 const struct GNUNET_GNSRECORD_Data *rd)
528{
529 struct RequestHandle *handle = cls;
530
531 handle->add_qe = NULL;
532 if (0 != strcmp (rec_name, handle->name))
533 {
534 GNUNET_break (0);
535 do_error (handle);
536 return;
537 }
538
539 if (0 != rd_count)
540 {
541 handle->proc (handle->proc_cls,
542 GNUNET_REST_create_response (NULL),
543 MHD_HTTP_CONFLICT);
544 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
545 return;
546 }
547
548 GNUNET_assert (NULL != handle->name);
549 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
550 &handle->zone_pkey,
551 handle->name,
552 handle->rd_count,
553 handle->rd,
554 &create_finished,
555 handle);
556}
557
558
559static void
560del_finished (void *cls,
561 int32_t success,
562 const char *emsg)
563{
564 struct RequestHandle *handle = cls;
565
566 handle->add_qe = NULL;
567 if (GNUNET_NO == success)
568 {
569 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
570 _("Deleting record failed, record does not exist%s%s\n"),
571 (NULL != emsg) ? ": " : "",
572 (NULL != emsg) ? emsg : "");
573 GNUNET_SCHEDULER_add_now (&do_error, handle); //do_not_found TODO
574 return;
575 }
576 if (GNUNET_SYSERR == success)
577 {
578 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
579 _("Deleting record failed%s%s\n"),
580 (NULL != emsg) ? ": " : "",
581 (NULL != emsg) ? emsg : "");
582 GNUNET_SCHEDULER_add_now (&do_error, handle);
583 return;
584 }
585 handle->proc (handle->proc_cls,
586 GNUNET_REST_create_response (NULL),
587 MHD_HTTP_NO_CONTENT);
588 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
589}
590
591
592static void
593del_cont (void *cls,
594 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
595 const char *label,
596 unsigned int rd_count,
597 const struct GNUNET_GNSRECORD_Data *rd)
598{
599 struct RequestHandle *handle = cls;
600
601 handle->add_qe = NULL;
602 if (0 == rd_count)
603 {
604 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
605 _("There are no records under label `%s' that could be deleted.\n"),
606 label);
607 do_error (handle);
608 return;
609 }
610
611 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
612 &handle->zone_pkey,
613 handle->name,
614 0, NULL,
615 &del_finished,
616 handle);
617}
618
619
620static void
621namestore_delete_cont (struct GNUNET_REST_RequestHandle *con,
622 const char *url,
623 void *cls)
624{
625 struct RequestHandle *handle = cls;
626
627 if (NULL == handle->name)
628 {
629 GNUNET_SCHEDULER_add_now (&do_error, handle);
630 return;
631 }
632
633 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
634 &handle->zone_pkey,
635 handle->name,
636 &do_error,
637 handle,
638 &del_cont,
639 handle);
640}
641
642
643static int
644json_to_gnsrecord (const json_t *records_json,
645 struct GNUNET_GNSRECORD_Data **rd,
646 unsigned int *rd_count)
647{
648 struct GNUNET_TIME_Relative etime_rel;
649 struct GNUNET_TIME_Absolute etime_abs;
650 char *value;
651 void *rdata;
652 size_t rdata_size;
653 const char *typestring;
654 const char *expirationstring;
655 json_t *type_json;
656 json_t *value_json;
657 json_t *record_json;
658 json_t *exp_json;
659
660 *rd_count = json_array_size (records_json);
661 *rd = GNUNET_new_array (*rd_count,
662 struct GNUNET_GNSRECORD_Data);
663 for (unsigned int i = 0; i < *rd_count; i++)
664 {
665 memset (&(*rd)[i],
666 0,
667 sizeof (struct GNUNET_GNSRECORD_Data));
668 record_json = json_array_get (records_json,
669 i);
670 type_json = json_object_get (record_json,
671 GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE);
672 if (! json_is_string (type_json))
673 {
674 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
675 "Type property is no string\n");
676 return GNUNET_SYSERR;
677 }
678 typestring = json_string_value (type_json);
679 (*rd)[i].record_type = GNUNET_GNSRECORD_typename_to_number (typestring);
680 if (UINT32_MAX == (*rd)[i].record_type)
681 {
682 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unsupported type `%s'\n"),
683 json_string_value (type_json));
684 return GNUNET_SYSERR;
685 }
686 value_json = json_object_get (record_json,
687 GNUNET_REST_JSONAPI_NAMESTORE_VALUE);
688 if (! json_is_string (value_json))
689 {
690 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
691 "Value property is no string\n");
692 return GNUNET_SYSERR;
693 }
694 value = GNUNET_strdup (json_string_value (value_json));
695 if (GNUNET_OK !=
696 GNUNET_GNSRECORD_string_to_value ((*rd)[i].record_type,
697 value,
698 &rdata,
699 &rdata_size))
700 {
701 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
702 _("Value `%s' invalid for record type `%s'\n"),
703 value,
704 typestring);
705 return GNUNET_SYSERR;
706 }
707 (*rd)[i].data = rdata;
708 (*rd)[i].data_size = rdata_size;
709 /**TODO
710 * if (1 == handle->is_shadow)
711 rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
712 if (1 != handle->is_public)
713 rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
714 */
715 exp_json = json_object_get (record_json,
716 GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION);
717 if (! json_is_string (exp_json))
718 {
719 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
720 "Expiration property is no string\n");
721 return GNUNET_SYSERR;
722 }
723 expirationstring = json_string_value (exp_json);
724 if (0 == strcmp (expirationstring, "never"))
725 {
726 (*rd)[i].expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
727 }
728 else if (GNUNET_OK ==
729 GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
730 &etime_rel))
731 {
732 (*rd)[i].expiration_time = etime_rel.rel_value_us;
733 (*rd)[i].flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
734 }
735 else if (GNUNET_OK ==
736 GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
737 &etime_abs))
738 {
739 (*rd)[i].expiration_time = etime_abs.abs_value_us;
740 }
741 else
742 {
743 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
744 _("Value `%s' invalid for record type `%s'\n"),
745 value,
746 typestring);
747 return GNUNET_SYSERR;
748 }
749 }
750 return GNUNET_OK;
751}
752
753
754static void
755namestore_create_cont (struct GNUNET_REST_RequestHandle *con,
756 const char *url,
757 void *cls)
758{
759 struct RequestHandle *handle = cls;
760 struct MHD_Response *resp;
761 struct GNUNET_JSONAPI_Document *json_obj;
762 struct GNUNET_JSONAPI_Resource *json_res;
763 json_t *records_json;
764 json_t *data_js;
765 json_error_t err;
766 char term_data[handle->rest_handle->data_size+1];
767 struct GNUNET_JSON_Specification docspec[] = {
768 GNUNET_JSON_spec_jsonapi_document (&json_obj),
769 GNUNET_JSON_spec_end()
770 };
771
772 if (strlen (GNUNET_REST_API_NS_NAMESTORE) != strlen (handle->url))
773 {
774 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
775 "Cannot create under %s\n", handle->url);
776 GNUNET_SCHEDULER_add_now (&do_error, handle);
777 return;
778 }
779 if (0 >= handle->rest_handle->data_size)
780 {
781 GNUNET_SCHEDULER_add_now (&do_error, handle);
782 return;
783 }
784 term_data[handle->rest_handle->data_size] = '\0';
785 GNUNET_memcpy (term_data,
786 handle->rest_handle->data,
787 handle->rest_handle->data_size);
788 data_js = json_loads (term_data,
789 JSON_DECODE_ANY,
790 &err);
791 GNUNET_assert (GNUNET_OK ==
792 GNUNET_JSON_parse (data_js, docspec,
793 NULL, NULL));
794 json_decref (data_js);
795 if (NULL == json_obj)
796 {
797 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
798 "Unable to parse JSONAPI Object from %s\n",
799 term_data);
800 GNUNET_SCHEDULER_add_now (&do_error, handle);
801 return;
802 }
803 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
804 {
805 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
806 "Cannot create more than 1 resource! (Got %d)\n",
807 GNUNET_JSONAPI_document_resource_count (json_obj));
808 GNUNET_JSONAPI_document_delete (json_obj);
809 GNUNET_SCHEDULER_add_now (&do_error, handle);
810 return;
811 }
812 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
813 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
814 GNUNET_REST_JSONAPI_NAMESTORE_RECORD))
815 {
816 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
817 "Unsupported JSON data type\n");
818 GNUNET_JSONAPI_document_delete (json_obj);
819 resp = GNUNET_REST_create_response (NULL);
820 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
821 cleanup_handle (handle);
822 return;
823 }
824 handle->name = GNUNET_strdup (GNUNET_JSONAPI_resource_get_id (json_res));
825 records_json = GNUNET_JSONAPI_resource_read_attr (json_res,
826 GNUNET_REST_JSONAPI_NAMESTORE_RECORD);
827 if (NULL == records_json)
828 {
829 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
830 "No records given\n");
831 GNUNET_JSONAPI_document_delete (json_obj);
832 GNUNET_SCHEDULER_add_now (&do_error, handle);
833 return;
834 }
835 if (GNUNET_SYSERR == json_to_gnsrecord (records_json, &handle->rd, &handle->rd_count))
836 {
837 GNUNET_JSONAPI_document_delete (json_obj);
838 GNUNET_SCHEDULER_add_now (&do_error, handle);
839 return;
840 }
841 GNUNET_JSONAPI_document_delete (json_obj);
842
843 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
844 &handle->zone_pkey,
845 handle->name,
846 &do_error,
847 handle,
848 &create_new_record_cont,
849 handle);
850}
851
852
853static void
854namestore_zkey_response (void *cls,
855 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
856 const char *label,
857 unsigned int rd_count,
858 const struct GNUNET_GNSRECORD_Data *rd)
859{
860 struct RequestHandle *handle = cls;
861 struct MHD_Response *resp;
862 struct GNUNET_JSONAPI_Document *json_obj;
863 struct GNUNET_JSONAPI_Resource *json_res;
864 json_t *name_json;
865 char* result;
866
867 handle->reverse_qe = NULL;
868 json_obj = GNUNET_JSONAPI_document_new ();
869 if (NULL != label)
870 {
871 name_json = json_string (label);
872 json_res = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_REVINFO,
873 handle->zkey_str);
874 GNUNET_JSONAPI_resource_add_attr (json_res,
875 GNUNET_REST_JSONAPI_NAMESTORE_NAME,
876 name_json);
877 GNUNET_JSONAPI_document_resource_add (json_obj, json_res);
878 json_decref (name_json);
879 }
880 //Handle response
881 if (GNUNET_SYSERR == GNUNET_JSONAPI_document_serialize (json_obj, &result))
882 {
883 GNUNET_JSONAPI_document_delete (json_obj);
884 GNUNET_SCHEDULER_add_now (&do_error, handle);
885 return;
886 }
887 resp = GNUNET_REST_create_response (result);
888 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
889 GNUNET_JSONAPI_document_delete (json_obj);
890 GNUNET_free (result);
891 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
892}
893
894
895static void
896namestore_zkey_cont (struct GNUNET_REST_RequestHandle *con,
897 const char *url,
898 void *cls)
899{
900 struct RequestHandle *handle = cls;
901 struct GNUNET_HashCode key;
902 struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
903
904 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_ZKEY,
905 strlen (GNUNET_REST_JSONAPI_NAMESTORE_ZKEY),
906 &key);
907 if ( GNUNET_NO ==
908 GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
909 &key) )
910 {
911 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
912 "No zkey given %s\n", handle->url);
913 GNUNET_SCHEDULER_add_now (&do_error, handle);
914 return;
915 }
916 handle->zkey_str = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
917 &key);
918 if ((NULL == handle->zkey_str) ||
919 (GNUNET_OK !=
920 GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->zkey_str,
921 strlen (handle->zkey_str),
922 &pubkey)))
923 {
924 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
925 "Zkey invalid %s\n", handle->zkey_str);
926 GNUNET_SCHEDULER_add_now (&do_error, handle);
927 return;
928 }
929 handle->reverse_qe = GNUNET_NAMESTORE_zone_to_name (handle->ns_handle,
930 &handle->zone_pkey,
931 &pubkey,
932 &do_error,
933 handle,
934 &namestore_zkey_response,
935 handle);
936}
937
938
939static void
940namestore_info_cont (struct GNUNET_REST_RequestHandle *con,
941 const char *url,
942 void *cls)
943{
944 struct RequestHandle *handle = cls;
945
946 handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
947 &handle->zone_pkey,
948 &do_error,
949 handle,
950 &namestore_list_response,
951 handle,
952 &namestore_list_finished,
953 handle);
954}
955
956
957static char*
958get_name_from_url (const char* url)
959{
960 if (strlen (url) <= strlen (GNUNET_REST_API_NS_NAMESTORE))
961 return NULL;
962 return (char*)url + strlen (GNUNET_REST_API_NS_NAMESTORE) + 1;
963}
964
965/**
966 * Respond to OPTIONS request
967 *
968 * @param con_handle the connection handle
969 * @param url the url
970 * @param cls the RequestHandle
971 */
972static void
973options_cont (struct GNUNET_REST_RequestHandle *con_handle,
974 const char* url,
975 void *cls)
976{
977 struct MHD_Response *resp;
978 struct RequestHandle *handle = cls;
979
980 //For now, independent of path return all options
981 resp = GNUNET_REST_create_response (NULL);
982 MHD_add_response_header (resp,
983 "Access-Control-Allow-Methods",
984 allow_methods);
985 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
986 cleanup_handle (handle);
987}
988
989
990/**
991 * Callback invoked from identity service with ego information.
992 * An @a ego of NULL means the ego was not found.
993 *
994 * @param cls closure with the configuration
995 * @param ego an ego known to identity service, or NULL
996 */
997static void
998identity_cb (void *cls,
999 const struct GNUNET_IDENTITY_Ego *ego)
1000{
1001 struct RequestHandle *handle = cls;
1002 struct MHD_Response *resp;
1003 struct GNUNET_REST_RequestHandlerError err;
1004 static const struct GNUNET_REST_RequestHandler handlers[] = {
1005 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE_ZKEY, &namestore_zkey_cont}, //reverse
1006 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_info_cont}, //list
1007 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_create_cont}, //create
1008 // {MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_NAMESTORE, &namestore_edit_cont}, //update. TODO this shoul be PATCH
1009 {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete_cont}, //delete
1010 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont},
1011 GNUNET_REST_HANDLER_END
1012 };
1013
1014 handle->ego_lookup = NULL;
1015 if (NULL == ego)
1016 {
1017 if (NULL != handle->ego_name)
1018 {
1019 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1020 _("Ego `%s' not known to identity service\n"),
1021 handle->ego_name);
1022 }
1023 resp = GNUNET_REST_create_response (NULL);
1024 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1025 cleanup_handle (handle);
1026 return;
1027 }
1028 handle->zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
1029 handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
1030 if (NULL == handle->ns_handle)
1031 {
1032 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1033 _("Failed to connect to namestore\n"));
1034 GNUNET_SCHEDULER_add_now (&do_error, handle);
1035 return;
1036 }
1037
1038 if (GNUNET_OK !=
1039 GNUNET_JSONAPI_handle_request (handle->rest_handle,
1040 handlers,
1041 &err,
1042 handle))
1043 {
1044 handle->response_code = err.error_code;
1045 GNUNET_SCHEDULER_add_now (&do_error,
1046 (void *) handle);
1047 }
1048}
1049
1050
1051static void
1052default_ego_cb (void *cls,
1053 struct GNUNET_IDENTITY_Ego *ego,
1054 void **ctx,
1055 const char *name)
1056{
1057 struct RequestHandle *handle = cls;
1058 struct MHD_Response *resp;
1059 handle->get_default = NULL;
1060 if (NULL == ego)
1061 {
1062 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1063 _("No default ego configured in identity service\n"));
1064 resp = GNUNET_REST_create_response (NULL);
1065 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1066 cleanup_handle (handle);
1067 return;
1068 }
1069 else
1070 {
1071 identity_cb (cls, ego);
1072 }
1073}
1074
1075static void
1076id_connect_cb (void *cls,
1077 struct GNUNET_IDENTITY_Ego *ego,
1078 void **ctx,
1079 const char *name)
1080{
1081 struct RequestHandle *handle = cls;
1082 if (NULL == ego)
1083 {
1084 handle->get_default = GNUNET_IDENTITY_get (handle->identity_handle,
1085 "namestore",
1086 &default_ego_cb, handle);
1087 }
1088}
1089
1090
1091/**
1092 * Function processing the REST call
1093 *
1094 * @param method HTTP method
1095 * @param url URL of the HTTP request
1096 * @param data body of the HTTP request (optional)
1097 * @param data_size length of the body
1098 * @param proc callback function for the result
1099 * @param proc_cls closure for callback function
1100 * @return #GNUNET_OK if request accepted
1101 */
1102static void
1103rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1104 GNUNET_REST_ResultProcessor proc,
1105 void *proc_cls)
1106{
1107 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1108 struct MHD_Response *resp;
1109 struct GNUNET_HashCode key;
1110 char *ego;
1111 char *name;
1112 char *type;
1113
1114 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1115 handle->proc_cls = proc_cls;
1116 handle->proc = proc;
1117 handle->rest_handle = rest_handle;
1118 handle->url = GNUNET_strdup (rest_handle->url);
1119 if (handle->url[strlen (handle->url)-1] == '/')
1120 handle->url[strlen (handle->url)-1] = '\0';
1121 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1122 "Connecting...\n");
1123 handle->cfg = cfg;
1124 ego = NULL;
1125 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_EGO,
1126 strlen (GNUNET_REST_JSONAPI_NAMESTORE_EGO),
1127 &key);
1128 if ( GNUNET_YES ==
1129 GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1130 &key) )
1131 {
1132 ego = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
1133 &key);
1134 }
1135
1136 handle->type = GNUNET_GNSRECORD_TYPE_ANY;
1137 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
1138 strlen (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE),
1139 &key);
1140 if ( GNUNET_YES ==
1141 GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1142 &key) )
1143 {
1144 type = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
1145 &key);
1146 if (NULL != type)
1147 handle->type = GNUNET_GNSRECORD_typename_to_number (type);
1148 }
1149 name = get_name_from_url (handle->url);
1150 if (NULL != ego)
1151 handle->ego_name = GNUNET_strdup (ego);
1152 if (NULL != name)
1153 handle->name = GNUNET_strdup (name);
1154 if (NULL == handle->ego_name)
1155 {
1156 handle->identity_handle = GNUNET_IDENTITY_connect (handle->cfg, &id_connect_cb, handle);
1157 if (NULL == handle->identity_handle)
1158 {
1159 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Cannot connect to identity service\n"));
1160 resp = GNUNET_REST_create_response (NULL);
1161 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1162 cleanup_handle (handle);
1163 }
1164 return;
1165 }
1166 handle->ego_lookup = GNUNET_IDENTITY_ego_lookup (cfg,
1167 handle->ego_name,
1168 &identity_cb,
1169 handle);
1170 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
1171 &do_timeout,
1172 handle);
1173}
1174
1175/**
1176 * Entry point for the plugin.
1177 *
1178 * @param cls Config info
1179 * @return NULL on error, otherwise the plugin context
1180 */
1181void *
1182libgnunet_plugin_rest_namestore_init (void *cls)
1183{
1184 static struct Plugin plugin;
1185 cfg = cls;
1186 struct GNUNET_REST_Plugin *api;
1187
1188 if (NULL != plugin.cfg)
1189 return NULL; /* can only initialize once! */
1190 memset (&plugin, 0, sizeof (struct Plugin));
1191 plugin.cfg = cfg;
1192 api = GNUNET_new (struct GNUNET_REST_Plugin);
1193 api->cls = &plugin;
1194 api->name = GNUNET_REST_API_NS_NAMESTORE;
1195 api->process_request = &rest_identity_process_request;
1196 GNUNET_asprintf (&allow_methods,
1197 "%s, %s, %s, %s, %s",
1198 MHD_HTTP_METHOD_GET,
1199 MHD_HTTP_METHOD_POST,
1200 MHD_HTTP_METHOD_PUT,
1201 MHD_HTTP_METHOD_DELETE,
1202 MHD_HTTP_METHOD_OPTIONS);
1203 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1204 _("Namestore REST API initialized\n"));
1205 return api;
1206}
1207
1208
1209/**
1210 * Exit point from the plugin.
1211 *
1212 * @param cls the plugin context (as returned by "init")
1213 * @return always NULL
1214 */
1215void *
1216libgnunet_plugin_rest_namestore_done (void *cls)
1217{
1218 struct GNUNET_REST_Plugin *api = cls;
1219 struct Plugin *plugin = api->cls;
1220
1221 plugin->cfg = NULL;
1222 GNUNET_free (api);
1223 GNUNET_free_non_null (allow_methods);
1224 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1225 "Namestore REST plugin is finished\n");
1226 return NULL;
1227}
1228
1229/* end of plugin_rest_namestore.c */