aboutsummaryrefslogtreecommitdiff
path: root/src/peerinfo-tool/plugin_rest_peerinfo.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/peerinfo-tool/plugin_rest_peerinfo.c')
-rw-r--r--src/peerinfo-tool/plugin_rest_peerinfo.c842
1 files changed, 0 insertions, 842 deletions
diff --git a/src/peerinfo-tool/plugin_rest_peerinfo.c b/src/peerinfo-tool/plugin_rest_peerinfo.c
deleted file mode 100644
index 13e2e863b..000000000
--- a/src/peerinfo-tool/plugin_rest_peerinfo.c
+++ /dev/null
@@ -1,842 +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 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Martin Schanzenbach
22 * @author Philippe Buschmann
23 * @file peerinfo/plugin_rest_peerinfo.c
24 * @brief GNUnet Peerinfo REST plugin
25 */
26
27#include "platform.h"
28#include "gnunet_rest_plugin.h"
29#include "gnunet_peerinfo_service.h"
30#include "gnunet_transport_service.h"
31#include "gnunet_rest_lib.h"
32#include "gnunet_json_lib.h"
33#include "microhttpd.h"
34#include <jansson.h>
35
36/**
37 * Peerinfo Namespace
38 */
39#define GNUNET_REST_API_NS_PEERINFO "/peerinfo"
40
41/**
42 * Peerinfo parameter peer
43 */
44#define GNUNET_REST_PEERINFO_PEER "peer"
45
46/**
47 * Peerinfo parameter friend
48 */
49#define GNUNET_REST_PEERINFO_FRIEND "friend"
50
51/**
52 * Peerinfo parameter array
53 */
54#define GNUNET_REST_PEERINFO_ARRAY "array"
55
56/**
57 * Error message Unknown Error
58 */
59#define GNUNET_REST_PEERINFO_ERROR_UNKNOWN "Unknown Error"
60
61/**
62 * How long until we time out during address lookup?
63 */
64#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
65/**
66 * The configuration handle
67 */
68const struct GNUNET_CONFIGURATION_Handle *cfg;
69
70/**
71 * HTTP methods allows for this plugin
72 */
73static char *allow_methods;
74
75/**
76 * Handle to PEERINFO
77 */
78static struct GNUNET_PEERINFO_Handle *peerinfo_handle;
79
80/**
81 * @brief struct returned by the initialization function of the plugin
82 */
83struct Plugin
84{
85 const struct GNUNET_CONFIGURATION_Handle *cfg;
86};
87
88
89/**
90 * Record we keep for each printable address.
91 */
92struct AddressRecord
93{
94 /**
95 * Current address-to-string context (if active, otherwise NULL).
96 */
97 struct GNUNET_TRANSPORT_AddressToStringContext *atsc;
98
99 /**
100 * Address expiration time
101 */
102 struct GNUNET_TIME_Absolute expiration;
103
104 /**
105 * Printable address.
106 */
107 char *result;
108
109 /**
110 * Print context this address record belongs to.
111 */
112 struct PrintContext *pc;
113};
114
115
116/**
117 * Structure we use to collect printable address information.
118 */
119struct PrintContext
120{
121 /**
122 * Kept in DLL.
123 */
124 struct PrintContext *next;
125
126 /**
127 * Kept in DLL.
128 */
129 struct PrintContext *prev;
130
131 /**
132 * Identity of the peer.
133 */
134 struct GNUNET_PeerIdentity peer;
135
136 /**
137 * List of printable addresses.
138 */
139 struct AddressRecord *address_list;
140
141 /**
142 * Number of completed addresses in @e address_list.
143 */
144 unsigned int num_addresses;
145
146 /**
147 * Number of addresses allocated in @e address_list.
148 */
149 unsigned int address_list_size;
150
151 /**
152 * Current offset in @e address_list (counted down).
153 */
154 unsigned int off;
155
156 /**
157 * Hello was friend only, #GNUNET_YES or #GNUNET_NO
158 */
159 int friend_only;
160
161 /**
162 * RequestHandle
163 */
164 struct RequestHandle *handle;
165};
166
167/**
168 * Head of list of print contexts.
169 */
170static struct PrintContext *pc_head;
171
172/**
173 * Tail of list of print contexts.
174 */
175static struct PrintContext *pc_tail;
176
177/**
178 * The request handle
179 */
180struct RequestHandle
181{
182 /**
183 * DLL
184 */
185 struct RequestHandle *next;
186
187 /**
188 * DLL
189 */
190 struct RequestHandle *prev;
191
192 /**
193 * JSON temporary array
194 */
195 json_t *temp_array;
196
197 /**
198 * Expiration time string
199 */
200 char *expiration_str;
201
202 /**
203 * Address string
204 */
205 const char *address;
206
207 /**
208 * Iteration peer public key
209 */
210 char *pubkey;
211
212 /**
213 * JSON response
214 */
215 json_t *response;
216
217 /**
218 * Handle to PEERINFO it
219 */
220 struct GNUNET_PEERINFO_IteratorContext *list_it;
221
222
223 /**
224 * Rest connection
225 */
226 struct GNUNET_REST_RequestHandle *rest_handle;
227
228 /**
229 * Desired timeout for the lookup (default is no timeout).
230 */
231 struct GNUNET_TIME_Relative timeout;
232
233 /**
234 * ID of a task associated with the resolution process.
235 */
236 struct GNUNET_SCHEDULER_Task *timeout_task;
237
238 /**
239 * The plugin result processor
240 */
241 GNUNET_REST_ResultProcessor proc;
242
243 /**
244 * The closure of the result processor
245 */
246 void *proc_cls;
247
248 /**
249 * The url
250 */
251 char *url;
252
253 /**
254 * Error response message
255 */
256 char *emsg;
257
258 /**
259 * Response code
260 */
261 int response_code;
262};
263
264/**
265 * DLL
266 */
267static struct RequestHandle *requests_head;
268
269/**
270 * DLL
271 */
272static struct RequestHandle *requests_tail;
273
274/**
275 * Cleanup lookup handle
276 * @param handle Handle to clean up
277 */
278static void
279cleanup_handle (void *cls)
280{
281 struct RequestHandle *handle = cls;
282
283 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
284 "Cleaning up\n");
285 if (NULL != handle->timeout_task)
286 {
287 GNUNET_SCHEDULER_cancel (handle->timeout_task);
288 handle->timeout_task = NULL;
289 }
290 if (NULL != handle->url)
291 GNUNET_free (handle->url);
292 if (NULL != handle->emsg)
293 GNUNET_free (handle->emsg);
294 if (NULL != handle->address)
295 GNUNET_free_nz ((char *) handle->address);
296 if (NULL != handle->expiration_str)
297 GNUNET_free (handle->expiration_str);
298 if (NULL != handle->pubkey)
299 GNUNET_free (handle->pubkey);
300
301 if (NULL != handle->temp_array)
302 {
303 json_decref (handle->temp_array);
304 handle->temp_array = NULL;
305 }
306 if (NULL != handle->response)
307 {
308 json_decref (handle->response);
309 handle->response = NULL;
310 }
311
312 if (NULL != handle->list_it)
313 {
314 GNUNET_PEERINFO_iterate_cancel (handle->list_it);
315 handle->list_it = NULL;
316 }
317 if (NULL != peerinfo_handle)
318 {
319 GNUNET_PEERINFO_disconnect (peerinfo_handle);
320 peerinfo_handle = NULL;
321 }
322 GNUNET_CONTAINER_DLL_remove (requests_head,
323 requests_tail,
324 handle);
325 GNUNET_free (handle);
326}
327
328
329/**
330 * Task run on errors. Reports an error and cleans up everything.
331 *
332 * @param cls the `struct RequestHandle`
333 */
334static void
335do_error (void *cls)
336{
337 struct RequestHandle *handle = cls;
338 struct MHD_Response *resp;
339 json_t *json_error = json_object ();
340 char *response;
341
342 if (NULL == handle->emsg)
343 handle->emsg = GNUNET_strdup (GNUNET_REST_PEERINFO_ERROR_UNKNOWN);
344
345 json_object_set_new (json_error, "error", json_string (handle->emsg));
346
347 if (0 == handle->response_code)
348 handle->response_code = MHD_HTTP_OK;
349 response = json_dumps (json_error, 0);
350 resp = GNUNET_REST_create_response (response);
351 MHD_add_response_header (resp, "Content-Type", "application/json");
352 handle->proc (handle->proc_cls, resp, handle->response_code);
353 json_decref (json_error);
354 GNUNET_free (response);
355 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
356}
357
358
359/**
360 * Function that assembles the response.
361 *
362 * @param cls the `struct RequestHandle`
363 */
364static void
365peerinfo_list_finished (void *cls)
366{
367 struct RequestHandle *handle = cls;
368 char *result_str;
369 struct MHD_Response *resp;
370
371 if (NULL == handle->response)
372 {
373 handle->response_code = MHD_HTTP_NOT_FOUND;
374 handle->emsg = GNUNET_strdup ("No peers found");
375 GNUNET_SCHEDULER_add_now (&do_error, handle);
376 return;
377 }
378
379 result_str = json_dumps (handle->response, 0);
380 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
381 resp = GNUNET_REST_create_response (result_str);
382 GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
383 "Content-Type",
384 "application/json"));
385 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
386 GNUNET_free (result_str);
387 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
388}
389
390
391/**
392 * Iterator callback to go over all addresses and count them.
393 *
394 * @param cls `struct PrintContext *` with `off` to increment
395 * @param address the address
396 * @param expiration expiration time
397 * @return #GNUNET_OK to keep the address and continue
398 */
399static int
400count_address (void *cls,
401 const struct GNUNET_HELLO_Address *address,
402 struct GNUNET_TIME_Absolute expiration)
403{
404 struct PrintContext *pc = cls;
405
406 if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
407 {
408 return GNUNET_OK; /* ignore expired address */
409 }
410
411 pc->off++;
412 return GNUNET_OK;
413}
414
415
416/**
417 * Print the collected address information to the console and free @a pc.
418 *
419 * @param pc printing context
420 */
421static void
422dump_pc (struct PrintContext *pc)
423{
424 struct RequestHandle *handle;
425 unsigned int i;
426 json_t *response_entry;
427 json_t *temp_array;
428 json_t *object;
429 json_t *address;
430 json_t *expires;
431 json_t *friend_and_peer_json;
432 char *friend_and_peer;
433
434 temp_array = json_array ();
435 response_entry = json_object ();
436
437 for (i = 0; i < pc->num_addresses; i++)
438 {
439 if (NULL != pc->address_list[i].result)
440 {
441 object = json_object ();
442 address = json_string (pc->address_list[i].result);
443 expires = json_string (
444 GNUNET_STRINGS_absolute_time_to_string (
445 pc->address_list[i].expiration));
446 json_object_set (object, "address", address);
447 json_object_set (object, "expires", expires);
448
449 json_decref (address);
450 json_decref (expires);
451
452 json_array_append (temp_array, object);
453 json_decref (object);
454 GNUNET_free (pc->address_list[i].result);
455 }
456 }
457
458 if (0 < json_array_size (temp_array))
459 {
460 GNUNET_asprintf (&friend_and_peer,
461 "%s%s",
462 (GNUNET_YES == pc->friend_only) ? "F2F:" : "",
463 GNUNET_i2s_full (&pc->peer));
464 friend_and_peer_json = json_string (friend_and_peer);
465 json_object_set (response_entry,
466 GNUNET_REST_PEERINFO_PEER,
467 friend_and_peer_json);
468 json_object_set (response_entry,
469 GNUNET_REST_PEERINFO_ARRAY,
470 temp_array);
471 json_array_append (pc->handle->response, response_entry);
472 json_decref (friend_and_peer_json);
473 GNUNET_free (friend_and_peer);
474 }
475
476 json_decref (temp_array);
477 json_decref (response_entry);
478
479 GNUNET_free (pc->address_list);
480 GNUNET_CONTAINER_DLL_remove (pc_head,
481 pc_tail,
482 pc);
483 handle = pc->handle;
484 GNUNET_free (pc);
485
486 if ((NULL == pc_head) &&
487 (NULL == handle->list_it))
488 {
489 GNUNET_SCHEDULER_add_now (&peerinfo_list_finished, handle);
490 }
491}
492
493
494/**
495 * Function to call with a human-readable format of an address
496 *
497 * @param cls closure
498 * @param address NULL on error, otherwise 0-terminated printable UTF-8 string
499 * @param res result of the address to string conversion:
500 * if #GNUNET_OK: address was valid (conversion to
501 * string might still have failed)
502 * if #GNUNET_SYSERR: address is invalid
503 */
504static void
505process_resolved_address (void *cls,
506 const char *address,
507 int res)
508{
509 struct AddressRecord *ar = cls;
510 struct PrintContext *pc = ar->pc;
511
512 if (NULL != address)
513 {
514 if (0 != strlen (address))
515 {
516 if (NULL != ar->result)
517 GNUNET_free (ar->result);
518 ar->result = GNUNET_strdup (address);
519 }
520 return;
521 }
522 ar->atsc = NULL;
523 if (GNUNET_SYSERR == res)
524 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
525 _ ("Failure: Cannot convert address to string for peer `%s'\n"),
526 GNUNET_i2s (&ar->pc->peer));
527 pc->num_addresses++;
528 if (pc->num_addresses == pc->address_list_size)
529 dump_pc (ar->pc);
530}
531
532
533/**
534 * Iterator callback to go over all addresses.
535 *
536 * @param cls closure
537 * @param address the address
538 * @param expiration expiration time
539 * @return #GNUNET_OK to keep the address and continue
540 */
541static int
542print_address (void *cls,
543 const struct GNUNET_HELLO_Address *address,
544 struct GNUNET_TIME_Absolute expiration)
545{
546 struct PrintContext *pc = cls;
547 struct AddressRecord *ar;
548
549 if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
550 {
551 return GNUNET_OK; /* ignore expired address */
552 }
553
554 GNUNET_assert (0 < pc->off);
555 ar = &pc->address_list[--pc->off];
556 ar->pc = pc;
557 ar->expiration = expiration;
558 GNUNET_asprintf (&ar->result,
559 "%s:%lu:%u",
560 address->transport_name,
561 (unsigned long) address->address_length,
562 address->local_info);
563 ar->atsc = GNUNET_TRANSPORT_address_to_string (cfg,
564 address,
565 GNUNET_NO,
566 TIMEOUT,
567 &process_resolved_address,
568 ar);
569 return GNUNET_OK;
570}
571
572
573/**
574 * Callback that processes each of the known HELLOs for the
575 * iteration response construction.
576 *
577 * @param cls closure, NULL
578 * @param peer id of the peer, NULL for last call
579 * @param hello hello message for the peer (can be NULL)
580 * @param err_msg message
581 */
582void
583peerinfo_list_iteration (void *cls,
584 const struct GNUNET_PeerIdentity *peer,
585 const struct GNUNET_HELLO_Message *hello,
586 const char *err_msg)
587{
588 struct RequestHandle *handle = cls;
589 struct PrintContext *pc;
590 int friend_only;
591
592 if (NULL == handle->response)
593 {
594 handle->response = json_array ();
595 }
596
597 if (NULL == peer)
598 {
599 handle->list_it = NULL;
600 handle->emsg = GNUNET_strdup ("Error in communication with peerinfo");
601 if (NULL != err_msg)
602 {
603 GNUNET_free (handle->emsg);
604 handle->emsg = GNUNET_strdup (err_msg);
605 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
606 }
607 if (NULL == pc_head)
608 GNUNET_SCHEDULER_add_now (&do_error, handle);
609 return;
610 }
611 if (NULL == hello)
612 return;
613
614 friend_only = GNUNET_NO;
615 if (NULL != hello)
616 friend_only = GNUNET_HELLO_is_friend_only (hello);
617
618 pc = GNUNET_new (struct PrintContext);
619 GNUNET_CONTAINER_DLL_insert (pc_head,
620 pc_tail,
621 pc);
622 pc->peer = *peer;
623 pc->friend_only = friend_only;
624 pc->handle = handle;
625 GNUNET_HELLO_iterate_addresses (hello,
626 GNUNET_NO,
627 &count_address,
628 pc);
629 if (0 == pc->off)
630 {
631 dump_pc (pc);
632 return;
633 }
634 pc->address_list_size = pc->off;
635 pc->address_list = GNUNET_malloc (
636 sizeof(struct AddressRecord) * pc->off);
637 GNUNET_HELLO_iterate_addresses (hello,
638 GNUNET_NO,
639 &print_address,
640 pc);
641}
642
643
644/**
645 * Handle peerinfo GET request
646 *
647 * @param con_handle the connection handle
648 * @param url the url
649 * @param cls the RequestHandle
650 */
651void
652peerinfo_get (struct GNUNET_REST_RequestHandle *con_handle,
653 const char*url,
654 void *cls)
655{
656 struct RequestHandle *handle = cls;
657 struct GNUNET_HashCode key;
658 const struct GNUNET_PeerIdentity *specific_peer;
659 // GNUNET_PEER_Id peer_id;
660 int include_friend_only;
661 char*include_friend_only_str;
662
663 include_friend_only = GNUNET_NO;
664 GNUNET_CRYPTO_hash (GNUNET_REST_PEERINFO_FRIEND,
665 strlen (GNUNET_REST_PEERINFO_FRIEND),
666 &key);
667 if (GNUNET_YES
668 == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
669 &key))
670 {
671 include_friend_only_str = GNUNET_CONTAINER_multihashmap_get (
672 con_handle->url_param_map, &key);
673 if (0 == strcmp (include_friend_only_str, "yes"))
674 {
675 include_friend_only = GNUNET_YES;
676 }
677 }
678
679 specific_peer = NULL;
680 GNUNET_CRYPTO_hash (GNUNET_REST_PEERINFO_PEER,
681 strlen (GNUNET_REST_PEERINFO_PEER),
682 &key);
683 if (GNUNET_YES
684 == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
685 &key))
686 {
687 // peer_id = *(unsigned int*)GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, &key);
688 // specific_peer = GNUNET_PEER_resolve2(peer_id);
689 }
690
691 handle->list_it = GNUNET_PEERINFO_iterate (peerinfo_handle,
692 include_friend_only,
693 specific_peer,
694 &peerinfo_list_iteration,
695 handle);
696}
697
698
699/**
700 * Respond to OPTIONS request
701 *
702 * @param con_handle the connection handle
703 * @param url the url
704 * @param cls the RequestHandle
705 */
706static void
707options_cont (struct GNUNET_REST_RequestHandle *con_handle,
708 const char*url,
709 void *cls)
710{
711 struct MHD_Response *resp;
712 struct RequestHandle *handle = cls;
713
714 // independent of path return all options
715 resp = GNUNET_REST_create_response (NULL);
716 MHD_add_response_header (resp,
717 "Access-Control-Allow-Methods",
718 allow_methods);
719 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
720 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
721 return;
722}
723
724
725/**
726 * Function processing the REST call
727 *
728 * @param method HTTP method
729 * @param url URL of the HTTP request
730 * @param data body of the HTTP request (optional)
731 * @param data_size length of the body
732 * @param proc callback function for the result
733 * @param proc_cls closure for callback function
734 * @return GNUNET_OK if request accepted
735 */
736static enum GNUNET_GenericReturnValue
737rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
738 GNUNET_REST_ResultProcessor proc,
739 void *proc_cls)
740{
741 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
742 struct GNUNET_REST_RequestHandlerError err;
743 static const struct GNUNET_REST_RequestHandler handlers[] = {
744 { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_PEERINFO, &peerinfo_get },
745 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_PEERINFO, &options_cont },
746 GNUNET_REST_HANDLER_END
747 };
748
749 handle->response_code = 0;
750 handle->timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
751 60);
752 handle->proc_cls = proc_cls;
753 handle->proc = proc;
754 handle->rest_handle = rest_handle;
755
756 handle->url = GNUNET_strdup (rest_handle->url);
757 if (handle->url[strlen (handle->url) - 1] == '/')
758 handle->url[strlen (handle->url) - 1] = '\0';
759 handle->timeout_task =
760 GNUNET_SCHEDULER_add_delayed (handle->timeout,
761 &do_error,
762 handle);
763 GNUNET_CONTAINER_DLL_insert (requests_head,
764 requests_tail,
765 handle);
766 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
767 if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
768 handlers,
769 &err,
770 handle))
771 {
772 cleanup_handle (handle);
773 return GNUNET_NO;
774 }
775 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
776 return GNUNET_YES;
777}
778
779
780/**
781 * Entry point for the plugin.
782 *
783 * @param cls Config info
784 * @return NULL on error, otherwise the plugin context
785 */
786void *
787libgnunet_plugin_rest_peerinfo_init (void *cls)
788{
789 static struct Plugin plugin;
790 struct GNUNET_REST_Plugin *api;
791
792 cfg = cls;
793 if (NULL != plugin.cfg)
794 return NULL; /* can only initialize once! */
795 memset (&plugin, 0, sizeof(struct Plugin));
796 plugin.cfg = cfg;
797 api = GNUNET_new (struct GNUNET_REST_Plugin);
798 api->cls = &plugin;
799 api->name = GNUNET_REST_API_NS_PEERINFO;
800 api->process_request = &rest_process_request;
801 GNUNET_asprintf (&allow_methods,
802 "%s, %s, %s, %s, %s",
803 MHD_HTTP_METHOD_GET,
804 MHD_HTTP_METHOD_POST,
805 MHD_HTTP_METHOD_PUT,
806 MHD_HTTP_METHOD_DELETE,
807 MHD_HTTP_METHOD_OPTIONS);
808 peerinfo_handle = GNUNET_PEERINFO_connect (cfg);
809
810 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
811 _ ("Peerinfo REST API initialized\n"));
812 return api;
813}
814
815
816/**
817 * Exit point from the plugin.
818 *
819 * @param cls the plugin context (as returned by "init")
820 * @return always NULL
821 */
822void *
823libgnunet_plugin_rest_peerinfo_done (void *cls)
824{
825 struct GNUNET_REST_Plugin *api = cls;
826 struct Plugin *plugin = api->cls;
827
828 plugin->cfg = NULL;
829 while (NULL != requests_head)
830 cleanup_handle (requests_head);
831 if (NULL != peerinfo_handle)
832 GNUNET_PEERINFO_disconnect (peerinfo_handle);
833
834 GNUNET_free (allow_methods);
835 GNUNET_free (api);
836 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
837 "Peerinfo REST plugin is finished\n");
838 return NULL;
839}
840
841
842/* end of plugin_rest_peerinfo.c */