aboutsummaryrefslogtreecommitdiff
path: root/src/namestore/plugin_rest_namestore.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/namestore/plugin_rest_namestore.c')
-rw-r--r--src/namestore/plugin_rest_namestore.c1105
1 files changed, 1105 insertions, 0 deletions
diff --git a/src/namestore/plugin_rest_namestore.c b/src/namestore/plugin_rest_namestore.c
new file mode 100644
index 000000000..26a037eae
--- /dev/null
+++ b/src/namestore/plugin_rest_namestore.c
@@ -0,0 +1,1105 @@
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 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Martin Schanzenbach
22 * @author Philippe Buschmann
23 * @file namestore/plugin_rest_namestore.c
24 * @brief GNUnet Namestore REST plugin
25 */
26
27#include "platform.h"
28#include "gnunet_rest_plugin.h"
29#include "gnunet_gns_service.h"
30#include "gnunet_namestore_service.h"
31#include "gnunet_identity_service.h"
32#include "gnunet_rest_lib.h"
33#include "gnunet_json_lib.h"
34#include "microhttpd.h"
35#include <jansson.h>
36
37/**
38 * Namestore Namespace
39 */
40#define GNUNET_REST_API_NS_NAMESTORE "/namestore"
41
42/**
43 * Error message Unknown Error
44 */
45#define GNUNET_REST_NAMESTORE_ERROR_UNKNOWN "Unknown Error"
46
47/**
48 * Error message No identity found
49 */
50#define GNUNET_REST_IDENTITY_NOT_FOUND "No identity found"
51
52/**
53 * Error message No default zone specified
54 */
55#define GNUNET_REST_NAMESTORE_NO_DEFAULT_ZONE "No default zone specified"
56
57/**
58 * Error message Failed request
59 */
60#define GNUNET_REST_NAMESTORE_FAILED "Namestore action failed"
61
62/**
63 * Error message invalid data
64 */
65#define GNUNET_REST_NAMESTORE_INVALID_DATA "Data invalid"
66
67/**
68 * Error message No data
69 */
70#define GNUNET_REST_NAMESTORE_NO_DATA "No data"
71
72/**
73 * State while collecting all egos
74 */
75#define ID_REST_STATE_INIT 0
76
77/**
78 * Done collecting egos
79 */
80#define ID_REST_STATE_POST_INIT 1
81/**
82 * The configuration handle
83 */
84const struct GNUNET_CONFIGURATION_Handle *cfg;
85
86/**
87 * HTTP methods allows for this plugin
88 */
89static char* allow_methods;
90
91/**
92 * @brief struct returned by the initialization function of the plugin
93 */
94struct Plugin
95{
96 const struct GNUNET_CONFIGURATION_Handle *cfg;
97};
98
99/**
100 * The default namestore ego
101 */
102struct EgoEntry
103{
104 /**
105 * DLL
106 */
107 struct EgoEntry *next;
108
109 /**
110 * DLL
111 */
112 struct EgoEntry *prev;
113
114 /**
115 * Ego Identifier
116 */
117 char *identifier;
118
119 /**
120 * Public key string
121 */
122 char *keystring;
123
124 /**
125 * The Ego
126 */
127 struct GNUNET_IDENTITY_Ego *ego;
128};
129
130/**
131 * The request handle
132 */
133struct RequestHandle
134{
135 /**
136 * Records to store
137 */
138 char *record_name;
139
140 /**
141 * Records to store
142 */
143 struct GNUNET_GNSRECORD_Data *rd;
144
145 /**
146 * NAMESTORE Operation
147 */
148 struct GNUNET_NAMESTORE_QueueEntry *add_qe;
149
150 /**
151 * Response object
152 */
153 json_t *resp_object;
154
155 /**
156 * The processing state
157 */
158 int state;
159
160 /**
161 * Handle to NAMESTORE
162 */
163 struct GNUNET_NAMESTORE_Handle *ns_handle;
164
165 /**
166 * Handle to NAMESTORE it
167 */
168 struct GNUNET_NAMESTORE_ZoneIterator *list_it;
169
170 /**
171 * Private key for the zone
172 */
173 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_pkey;
174
175 /**
176 * IDENTITY Operation
177 */
178 struct EgoEntry *ego_entry;
179
180 /**
181 * Ego list
182 */
183 struct EgoEntry *ego_head;
184
185 /**
186 * Ego list
187 */
188 struct EgoEntry *ego_tail;
189
190 /**
191 * IDENTITY Operation
192 */
193 struct GNUNET_IDENTITY_Operation *op;
194
195 /**
196 * Handle to Identity service.
197 */
198 struct GNUNET_IDENTITY_Handle *identity_handle;
199
200 /**
201 * Rest connection
202 */
203 struct GNUNET_REST_RequestHandle *rest_handle;
204
205 /**
206 * Desired timeout for the lookup (default is no timeout).
207 */
208 struct GNUNET_TIME_Relative timeout;
209
210 /**
211 * ID of a task associated with the resolution process.
212 */
213 struct GNUNET_SCHEDULER_Task *timeout_task;
214
215 /**
216 * The plugin result processor
217 */
218 GNUNET_REST_ResultProcessor proc;
219
220 /**
221 * The closure of the result processor
222 */
223 void *proc_cls;
224
225 /**
226 * The url
227 */
228 char *url;
229
230 /**
231 * Error response message
232 */
233 char *emsg;
234
235 /**
236 * Response code
237 */
238 int response_code;
239
240};
241
242/**
243 * Cleanup lookup handle
244 * @param handle Handle to clean up
245 */
246static void
247cleanup_handle (void *cls)
248{
249 struct RequestHandle *handle = cls;
250 struct EgoEntry *ego_entry;
251 struct EgoEntry *ego_tmp;
252
253 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
254 "Cleaning up\n");
255 if (NULL != handle->timeout_task)
256 {
257 GNUNET_SCHEDULER_cancel (handle->timeout_task);
258 handle->timeout_task = NULL;
259 }
260 if (NULL != handle->record_name)
261 GNUNET_free(handle->record_name);
262 if (NULL != handle->url)
263 GNUNET_free(handle->url);
264 if (NULL != handle->emsg)
265 GNUNET_free(handle->emsg);
266 if (NULL != handle->rd)
267 {
268 if (NULL != handle->rd->data)
269 GNUNET_free((void*)handle->rd->data);
270 GNUNET_free(handle->rd);
271 }
272 if (NULL != handle->timeout_task)
273 GNUNET_SCHEDULER_cancel(handle->timeout_task);
274 if (NULL != handle->list_it)
275 GNUNET_NAMESTORE_zone_iteration_stop(handle->list_it);
276 if (NULL != handle->add_qe)
277 GNUNET_NAMESTORE_cancel(handle->add_qe);
278 if (NULL != handle->identity_handle)
279 GNUNET_IDENTITY_disconnect(handle->identity_handle);
280 if (NULL != handle->ns_handle)
281 {
282 GNUNET_NAMESTORE_disconnect(handle->ns_handle);
283 }
284
285 for (ego_entry = handle->ego_head;
286 NULL != ego_entry;)
287 {
288 ego_tmp = ego_entry;
289 ego_entry = ego_entry->next;
290 GNUNET_free(ego_tmp->identifier);
291 GNUNET_free(ego_tmp->keystring);
292 GNUNET_free(ego_tmp);
293 }
294
295 if(NULL != handle->resp_object)
296 {
297 json_decref(handle->resp_object);
298 }
299
300 GNUNET_free (handle);
301}
302
303
304/**
305 * Task run on errors. Reports an error and cleans up everything.
306 *
307 * @param cls the `struct RequestHandle`
308 */
309static void
310do_error (void *cls)
311{
312 struct RequestHandle *handle = cls;
313 struct MHD_Response *resp;
314 json_t *json_error = json_object();
315 char *response;
316
317 if (NULL == handle->emsg)
318 handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_ERROR_UNKNOWN);
319
320 json_object_set_new(json_error,"error", json_string(handle->emsg));
321
322 if (0 == handle->response_code)
323 handle->response_code = MHD_HTTP_OK;
324 response = json_dumps (json_error, 0);
325 resp = GNUNET_REST_create_response (response);
326 handle->proc (handle->proc_cls, resp, handle->response_code);
327 json_decref(json_error);
328 GNUNET_free(response);
329 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
330}
331
332
333/**
334 * Get EgoEntry from list with either a public key or a name
335 * If public key and name are not NULL, it returns the public key result first
336 *
337 * @param handle the RequestHandle
338 * @param pubkey the public key of an identity (only one can be NULL)
339 * @param name the name of an identity (only one can be NULL)
340 * @return EgoEntry or NULL if not found
341 */
342struct EgoEntry*
343get_egoentry_namestore(struct RequestHandle *handle, char *name)
344{
345 struct EgoEntry *ego_entry;
346 if (NULL != name)
347 {
348 for (ego_entry = handle->ego_head;
349 NULL != ego_entry;
350 ego_entry = ego_entry->next)
351 {
352 if (0 != strcasecmp (name, ego_entry->identifier))
353 continue;
354 return ego_entry;
355 }
356 }
357 return NULL;
358}
359
360
361/**
362 * Does internal server error when iteration failed.
363 *
364 * @param cls the `struct RequestHandle`
365 */
366static void
367namestore_iteration_error (void *cls)
368{
369 struct RequestHandle *handle = cls;
370 handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED);
371 GNUNET_SCHEDULER_add_now (&do_error, handle);
372 return;
373}
374
375
376/**
377 * Create finished callback
378 *
379 * @param cls the `struct RequestHandle`
380 * @param success the success indicating integer, GNUNET_OK on success
381 * @param emsg the error message (can be NULL)
382 */
383static void
384create_finished (void *cls, int32_t success, const char *emsg)
385{
386 struct RequestHandle *handle = cls;
387 struct MHD_Response *resp;
388
389 handle->add_qe = NULL;
390 if (GNUNET_YES != success)
391 {
392 if (NULL != emsg)
393 {
394 handle->emsg = GNUNET_strdup(emsg);
395 GNUNET_SCHEDULER_add_now (&do_error, handle);
396 return;
397 }
398 handle->emsg = GNUNET_strdup("Error storing records");
399 GNUNET_SCHEDULER_add_now (&do_error, handle);
400 return;
401 }
402 resp = GNUNET_REST_create_response (NULL);
403 handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
404 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
405}
406
407
408/**
409 * Delete finished callback
410 *
411 * @param cls the `struct RequestHandle`
412 * @param success the success indicating integer, GNUNET_OK on success
413 * @param emsg the error message (can be NULL)
414 */
415static void
416del_finished (void *cls, int32_t success, const char *emsg)
417{
418 struct RequestHandle *handle = cls;
419
420 handle->add_qe = NULL;
421 if (GNUNET_NO == success)
422 {
423 handle->response_code = MHD_HTTP_NOT_FOUND;
424 handle->emsg = GNUNET_strdup("No record found");
425 GNUNET_SCHEDULER_add_now (&do_error, handle);
426 return;
427 }
428 if (GNUNET_SYSERR == success)
429 {
430 if (NULL != emsg)
431 {
432 handle->emsg = GNUNET_strdup(emsg);
433 GNUNET_SCHEDULER_add_now (&do_error, handle);
434 return;
435 }
436 handle->emsg = GNUNET_strdup("Deleting record failed");
437 GNUNET_SCHEDULER_add_now (&do_error, handle);
438 return;
439 }
440 handle->proc (handle->proc_cls,
441 GNUNET_REST_create_response (NULL),
442 MHD_HTTP_NO_CONTENT);
443 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
444}
445
446
447/**
448 * Iteration over all results finished, build final
449 * response.
450 *
451 * @param cls the `struct RequestHandle`
452 */
453static void
454namestore_list_finished (void *cls)
455{
456 struct RequestHandle *handle = cls;
457 char *result_str;
458 struct MHD_Response *resp;
459
460 handle->list_it = NULL;
461
462 if (NULL == handle->resp_object)
463 handle->resp_object = json_array();
464
465 result_str = json_dumps (handle->resp_object, 0);
466 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
467 resp = GNUNET_REST_create_response (result_str);
468 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
469 GNUNET_free_non_null (result_str);
470 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
471}
472
473
474/**
475 * Create a response with requested records
476 *
477 * @param handle the RequestHandle
478 */
479static void
480namestore_list_iteration (void *cls,
481 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
482 const char *rname,
483 unsigned int rd_len,
484 const struct GNUNET_GNSRECORD_Data *rd)
485{
486 struct RequestHandle *handle = cls;
487 json_t *record_obj;
488
489 if (NULL == handle->resp_object)
490 handle->resp_object = json_array();
491
492 for (unsigned int i = 0; i < rd_len; i++)
493 {
494 if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
495 (0 != strcmp (rname, GNUNET_GNS_EMPTY_LABEL_AT)) )
496 continue;
497
498 record_obj = GNUNET_JSON_from_gns_record(rname,rd);
499
500 if(NULL == record_obj)
501 continue;
502
503 json_array_append (handle->resp_object, record_obj);
504 json_decref (record_obj);
505 }
506
507 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it, 1);
508}
509
510/**
511 * @param cls closure
512 * @param ego ego handle
513 * @param ctx context for application to store data for this ego
514 * (during the lifetime of this process, initially NULL)
515 * @param identifier identifier assigned by the user for this ego,
516 * NULL if the user just deleted the ego and it
517 * must thus no longer be used
518 */
519static void
520default_ego_get (void *cls,
521 struct GNUNET_IDENTITY_Ego *ego,
522 void **ctx,
523 const char *identifier)
524{
525 struct RequestHandle *handle = cls;
526 handle->op = NULL;
527
528 if (ego == NULL)
529 {
530 handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_NO_DEFAULT_ZONE);
531 GNUNET_SCHEDULER_add_now (&do_error, handle);
532 return;
533 }
534 handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego);
535
536 handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
537 handle->zone_pkey,
538 &namestore_iteration_error,
539 handle,
540 &namestore_list_iteration,
541 handle,
542 &namestore_list_finished,
543 handle);
544 if (NULL == handle->list_it)
545 {
546 handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED);
547 GNUNET_SCHEDULER_add_now (&do_error, handle);
548 return;
549 }
550}
551
552
553/**
554 * Handle namestore GET request
555 *
556 * @param con_handle the connection handle
557 * @param url the url
558 * @param cls the RequestHandle
559 */
560void
561namestore_get (struct GNUNET_REST_RequestHandle *con_handle,
562 const char* url,
563 void *cls)
564{
565 struct RequestHandle *handle = cls;
566 struct EgoEntry *ego_entry;
567 char *egoname;
568
569 egoname = NULL;
570 ego_entry = NULL;
571
572 //set zone to name if given
573 if (strlen (GNUNET_REST_API_NS_NAMESTORE) < strlen (handle->url))
574 {
575 egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE)+1];
576 ego_entry = get_egoentry_namestore(handle, egoname);
577
578 if (NULL == ego_entry)
579 {
580 handle->response_code = MHD_HTTP_NOT_FOUND;
581 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
582 GNUNET_SCHEDULER_add_now (&do_error, handle);
583 return;
584 }
585 }
586 if ( NULL != ego_entry )
587 {
588 handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego);
589 }
590
591 if (NULL == handle->zone_pkey)
592 {
593 handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
594 "namestore",
595 &default_ego_get,
596 handle);
597 return;
598 }
599 handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
600 handle->zone_pkey,
601 &namestore_iteration_error,
602 handle,
603 &namestore_list_iteration,
604 handle,
605 &namestore_list_finished,
606 handle);
607 if (NULL == handle->list_it)
608 {
609 handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED);
610 GNUNET_SCHEDULER_add_now (&do_error, handle);
611 return;
612 }
613}
614
615
616/**
617 * @param cls closure
618 * @param ego ego handle
619 * @param ctx context for application to store data for this ego
620 * (during the lifetime of this process, initially NULL)
621 * @param identifier identifier assigned by the user for this ego,
622 * NULL if the user just deleted the ego and it
623 * must thus no longer be used
624 */
625static void
626default_ego_post (void *cls,
627 struct GNUNET_IDENTITY_Ego *ego,
628 void **ctx,
629 const char *identifier)
630{
631 struct RequestHandle *handle = cls;
632 handle->op = NULL;
633
634 if (ego == NULL)
635 {
636 handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_NO_DEFAULT_ZONE);
637 GNUNET_SCHEDULER_add_now (&do_error, handle);
638 return;
639 }
640 handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego);
641
642 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
643 handle->zone_pkey,
644 handle->record_name,
645 1,
646 handle->rd,
647 &create_finished,
648 handle);
649 if (NULL == handle->add_qe)
650 {
651 handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED);
652 GNUNET_SCHEDULER_add_now (&do_error, handle);
653 return;
654 }
655}
656
657
658/**
659 * Handle namestore POST request
660 *
661 * @param con_handle the connection handle
662 * @param url the url
663 * @param cls the RequestHandle
664 */
665void
666namestore_add (struct GNUNET_REST_RequestHandle *con_handle,
667 const char* url,
668 void *cls)
669{
670 struct RequestHandle *handle = cls;
671 struct GNUNET_GNSRECORD_Data *gns_record;
672 struct EgoEntry *ego_entry;
673 char *egoname;
674 json_t *data_js;
675 json_t *name_json;
676 json_error_t err;
677 char term_data[handle->rest_handle->data_size + 1];
678
679 struct GNUNET_JSON_Specification gnsspec[] = {
680 GNUNET_JSON_spec_gnsrecord_data(&gns_record),
681 GNUNET_JSON_spec_end ()
682 };
683
684 if (0 >= handle->rest_handle->data_size)
685 {
686 handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_NO_DATA);
687 GNUNET_SCHEDULER_add_now (&do_error, handle);
688 return;
689 }
690 term_data[handle->rest_handle->data_size] = '\0';
691 GNUNET_memcpy(term_data, handle->rest_handle->data,
692 handle->rest_handle->data_size);
693 data_js = json_loads (term_data, JSON_DECODE_ANY, &err);
694 if (GNUNET_OK != GNUNET_JSON_parse (data_js, gnsspec, NULL, NULL))
695 {
696 handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_INVALID_DATA);
697 GNUNET_SCHEDULER_add_now (&do_error, handle);
698 GNUNET_JSON_parse_free(gnsspec);
699 json_decref (data_js);
700 return;
701 }
702 handle->rd = gns_record;
703
704 name_json = json_object_get(data_js, "record_name");
705 if (!json_is_string(name_json))
706 {
707 handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_INVALID_DATA);
708 GNUNET_SCHEDULER_add_now (&do_error, handle);
709 json_decref (data_js);
710 return;
711 }
712 handle->record_name = GNUNET_strdup(json_string_value(name_json));
713 if(NULL == handle->record_name)
714 {
715 handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_INVALID_DATA);
716 GNUNET_SCHEDULER_add_now (&do_error, handle);
717 json_decref (data_js);
718 return;
719 }
720 if (0 >= strlen(handle->record_name))
721 {
722 handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_INVALID_DATA);
723 GNUNET_SCHEDULER_add_now (&do_error, handle);
724 json_decref (data_js);
725 return;
726 }
727 json_decref (data_js);
728
729 egoname = NULL;
730 ego_entry = NULL;
731
732 //set zone to name if given
733 if (strlen (GNUNET_REST_API_NS_NAMESTORE) < strlen (handle->url))
734 {
735 egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE)+1];
736 ego_entry = get_egoentry_namestore(handle, egoname);
737
738 if (NULL == ego_entry)
739 {
740 handle->response_code = MHD_HTTP_NOT_FOUND;
741 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
742 GNUNET_SCHEDULER_add_now (&do_error, handle);
743 return;
744 }
745 }
746 if (NULL != ego_entry)
747 {
748 handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego);
749 }
750 if (NULL == handle->zone_pkey)
751 {
752 handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
753 "namestore",
754 &default_ego_post,
755 handle);
756 return;
757 }
758 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
759 handle->zone_pkey,
760 handle->record_name,
761 1,
762 handle->rd,
763 &create_finished,
764 handle);
765 if (NULL == handle->add_qe)
766 {
767 handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED);
768 GNUNET_SCHEDULER_add_now (&do_error, handle);
769 return;
770 }
771}
772
773
774/**
775 * @param cls closure
776 * @param ego ego handle
777 * @param ctx context for application to store data for this ego
778 * (during the lifetime of this process, initially NULL)
779 * @param identifier identifier assigned by the user for this ego,
780 * NULL if the user just deleted the ego and it
781 * must thus no longer be used
782 */
783static void
784default_ego_delete (void *cls,
785 struct GNUNET_IDENTITY_Ego *ego,
786 void **ctx,
787 const char *identifier)
788{
789 struct RequestHandle *handle = cls;
790 handle->op = NULL;
791
792 if (ego == NULL)
793 {
794 handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_NO_DEFAULT_ZONE);
795 GNUNET_SCHEDULER_add_now (&do_error, handle);
796 return;
797 }
798 handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego);
799
800 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
801 handle->zone_pkey,
802 handle->record_name,
803 0,
804 NULL,
805 &del_finished,
806 handle);
807 if (NULL == handle->add_qe)
808 {
809 handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED);
810 GNUNET_SCHEDULER_add_now (&do_error, handle);
811 return;
812 }
813}
814
815
816/**
817 * Handle namestore DELETE request
818 *
819 * @param con_handle the connection handle
820 * @param url the url
821 * @param cls the RequestHandle
822 */
823void
824namestore_delete (struct GNUNET_REST_RequestHandle *con_handle,
825 const char* url,
826 void *cls)
827{
828 struct RequestHandle *handle = cls;
829 struct GNUNET_HashCode key;
830 struct EgoEntry *ego_entry;
831 char *egoname;
832
833 egoname = NULL;
834 ego_entry = NULL;
835
836 //set zone to name if given
837 if (strlen (GNUNET_REST_API_NS_NAMESTORE) < strlen (handle->url))
838 {
839 egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE)+1];
840 ego_entry = get_egoentry_namestore(handle, egoname);
841
842 if (NULL == ego_entry)
843 {
844 handle->response_code = MHD_HTTP_NOT_FOUND;
845 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
846 GNUNET_SCHEDULER_add_now (&do_error, handle);
847 return;
848 }
849 }
850 if ( NULL != ego_entry )
851 {
852 handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego);
853 }
854
855 GNUNET_CRYPTO_hash ("record_name", strlen ("record_name"), &key);
856 if ( GNUNET_NO
857 == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
858 &key))
859 {
860 handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_INVALID_DATA);
861 GNUNET_SCHEDULER_add_now (&do_error, handle);
862 return;
863 }
864 handle->record_name = GNUNET_strdup(
865 GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, &key));
866
867 if (NULL == handle->zone_pkey)
868 {
869 handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
870 "namestore",
871 &default_ego_delete,
872 handle);
873 return;
874 }
875
876 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
877 handle->zone_pkey,
878 handle->record_name,
879 0,
880 NULL,
881 &del_finished,
882 handle);
883 if (NULL == handle->add_qe)
884 {
885 handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED);
886 GNUNET_SCHEDULER_add_now (&do_error, handle);
887 return;
888 }
889}
890
891
892
893/**
894 * Respond to OPTIONS request
895 *
896 * @param con_handle the connection handle
897 * @param url the url
898 * @param cls the RequestHandle
899 */
900static void
901options_cont (struct GNUNET_REST_RequestHandle *con_handle,
902 const char* url,
903 void *cls)
904{
905 struct MHD_Response *resp;
906 struct RequestHandle *handle = cls;
907
908 //independent of path return all options
909 resp = GNUNET_REST_create_response (NULL);
910 MHD_add_response_header (resp,
911 "Access-Control-Allow-Methods",
912 allow_methods);
913 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
914 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
915 return;
916}
917
918
919/**
920 * Handle rest request
921 *
922 * @param handle the request handle
923 */
924static void
925init_cont (struct RequestHandle *handle)
926{
927 struct GNUNET_REST_RequestHandlerError err;
928 static const struct GNUNET_REST_RequestHandler handlers[] = {
929 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_get},
930 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_add},
931 {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete},
932 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont},
933 GNUNET_REST_HANDLER_END
934 };
935
936 if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
937 handlers,
938 &err,
939 handle))
940 {
941 handle->response_code = err.error_code;
942 GNUNET_SCHEDULER_add_now (&do_error, handle);
943 }
944}
945
946
947/**
948 * This function is initially called for all egos and then again
949 * whenever a ego's identifier changes or if it is deleted. At the
950 * end of the initial pass over all egos, the function is once called
951 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
952 * be invoked in the future or that there was an error.
953 *
954 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
955 * this function is only called ONCE, and 'NULL' being passed in
956 * 'ego' does indicate an error (i.e. name is taken or no default
957 * value is known). If 'ego' is non-NULL and if '*ctx'
958 * is set in those callbacks, the value WILL be passed to a subsequent
959 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
960 * that one was not NULL).
961 *
962 * When an identity is renamed, this function is called with the
963 * (known) ego but the NEW identifier.
964 *
965 * When an identity is deleted, this function is called with the
966 * (known) ego and "NULL" for the 'identifier'. In this case,
967 * the 'ego' is henceforth invalid (and the 'ctx' should also be
968 * cleaned up).
969 *
970 * @param cls closure
971 * @param ego ego handle
972 * @param ctx context for application to store data for this ego
973 * (during the lifetime of this process, initially NULL)
974 * @param name identifier assigned by the user for this ego,
975 * NULL if the user just deleted the ego and it
976 * must thus no longer be used
977 */
978static void
979id_connect_cb (void *cls,
980 struct GNUNET_IDENTITY_Ego *ego,
981 void **ctx,
982 const char *name)
983{
984 struct RequestHandle *handle = cls;
985 struct EgoEntry *ego_entry;
986 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
987
988 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
989 {
990 handle->state = ID_REST_STATE_POST_INIT;
991 init_cont(handle);
992 return;
993 }
994 if (ID_REST_STATE_INIT == handle->state)
995 {
996 ego_entry = GNUNET_new(struct EgoEntry);
997 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
998 ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
999 ego_entry->ego = ego;
1000 GNUNET_asprintf (&ego_entry->identifier, "%s", name);
1001 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head, handle->ego_tail,
1002 ego_entry);
1003 }
1004
1005}
1006
1007
1008/**
1009 * Function processing the REST call
1010 *
1011 * @param method HTTP method
1012 * @param url URL of the HTTP request
1013 * @param data body of the HTTP request (optional)
1014 * @param data_size length of the body
1015 * @param proc callback function for the result
1016 * @param proc_cls closure for callback function
1017 * @return GNUNET_OK if request accepted
1018 */
1019static void
1020rest_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1021 GNUNET_REST_ResultProcessor proc,
1022 void *proc_cls)
1023{
1024 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1025
1026 handle->response_code = 0;
1027 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1028 handle->proc_cls = proc_cls;
1029 handle->proc = proc;
1030 handle->rest_handle = rest_handle;
1031 handle->zone_pkey = NULL;
1032
1033 handle->url = GNUNET_strdup (rest_handle->url);
1034 if (handle->url[strlen (handle->url)-1] == '/')
1035 handle->url[strlen (handle->url)-1] = '\0';
1036 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
1037
1038 handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
1039 handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &id_connect_cb, handle);
1040 handle->timeout_task =
1041 GNUNET_SCHEDULER_add_delayed (handle->timeout,
1042 &do_error,
1043 handle);
1044
1045 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
1046}
1047
1048
1049/**
1050 * Entry point for the plugin.
1051 *
1052 * @param cls Config info
1053 * @return NULL on error, otherwise the plugin context
1054 */
1055void *
1056libgnunet_plugin_rest_namestore_init (void *cls)
1057{
1058 static struct Plugin plugin;
1059 struct GNUNET_REST_Plugin *api;
1060
1061 cfg = cls;
1062 if (NULL != plugin.cfg)
1063 return NULL; /* can only initialize once! */
1064 memset (&plugin, 0, sizeof (struct Plugin));
1065 plugin.cfg = cfg;
1066 api = GNUNET_new (struct GNUNET_REST_Plugin);
1067 api->cls = &plugin;
1068 api->name = GNUNET_REST_API_NS_NAMESTORE;
1069 api->process_request = &rest_process_request;
1070 GNUNET_asprintf (&allow_methods,
1071 "%s, %s, %s, %s, %s",
1072 MHD_HTTP_METHOD_GET,
1073 MHD_HTTP_METHOD_POST,
1074 MHD_HTTP_METHOD_PUT,
1075 MHD_HTTP_METHOD_DELETE,
1076 MHD_HTTP_METHOD_OPTIONS);
1077
1078 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1079 _("Namestore REST API initialized\n"));
1080 return api;
1081}
1082
1083
1084/**
1085 * Exit point from the plugin.
1086 *
1087 * @param cls the plugin context (as returned by "init")
1088 * @return always NULL
1089 */
1090void *
1091libgnunet_plugin_rest_namestore_done (void *cls)
1092{
1093 struct GNUNET_REST_Plugin *api = cls;
1094 struct Plugin *plugin = api->cls;
1095 plugin->cfg = NULL;
1096
1097 GNUNET_free_non_null (allow_methods);
1098 GNUNET_free (api);
1099 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1100 "Namestore REST plugin is finished\n");
1101 return NULL;
1102}
1103
1104/* end of plugin_rest_namestore.c */
1105