2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file experimentation/gnunet-daemon-experimentation_nodes.c
23 * @brief experimentation daemon: node management
24 * @author Christian Grothoff
25 * @author Matthias Wachs
28 #include "gnunet_getopt_lib.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_core_service.h"
31 #include "gnunet_statistics_service.h"
32 #include "gnunet-daemon-experimentation.h"
35 #define FAST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
39 static struct GNUNET_CORE_Handle *ch;
45 static struct GNUNET_PeerIdentity me;
49 * Nodes with a pending request
51 struct GNUNET_CONTAINER_MultiHashMap *nodes_requested;
55 * Active experimentation nodes
57 struct GNUNET_CONTAINER_MultiHashMap *nodes_active;
61 * Inactive experimentation nodes
62 * To be excluded from future requests
64 struct GNUNET_CONTAINER_MultiHashMap *nodes_inactive;
70 * @param m hashmap to update values from
72 static void update_stats (struct GNUNET_CONTAINER_MultiHashMap *m)
74 GNUNET_assert (NULL != m);
75 GNUNET_assert (NULL != GED_stats);
77 if (m == nodes_active)
79 GNUNET_STATISTICS_set (GED_stats, "# nodes active",
80 GNUNET_CONTAINER_multihashmap_size(m), GNUNET_NO);
82 else if (m == nodes_inactive)
84 GNUNET_STATISTICS_set (GED_stats, "# nodes inactive",
85 GNUNET_CONTAINER_multihashmap_size(m), GNUNET_NO);
87 else if (m == nodes_requested)
89 GNUNET_STATISTICS_set (GED_stats, "# nodes requested",
90 GNUNET_CONTAINER_multihashmap_size(m), GNUNET_NO);
101 * @param cls the hashmap to clean up
102 * @param key key of the current node
103 * @param value related node object
104 * @return always GNUNET_OK
107 cleanup_nodes (void *cls,
108 const struct GNUNET_HashCode * key,
112 struct GNUNET_CONTAINER_MultiHashMap *cur = cls;
115 if (GNUNET_SCHEDULER_NO_TASK != n->timeout_task)
117 GNUNET_SCHEDULER_cancel (n->timeout_task);
118 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
122 GNUNET_CORE_notify_transmit_ready_cancel (n->cth);
125 GNUNET_free_non_null (n->issuer_id);
127 GNUNET_CONTAINER_multihashmap_remove (cur, key, value);
134 * Check if id passed is my id
136 * @param id the id to check
137 * @return GNUNET_YES or GNUNET_NO
139 static int is_me (const struct GNUNET_PeerIdentity *id)
141 if (0 == memcmp (&me, id, sizeof (me)))
148 * Core startup callback
151 * @param server core service's server handle
152 * @param my_identity my id
155 core_startup_handler (void *cls,
156 struct GNUNET_CORE_Handle *server,
157 const struct GNUNET_PeerIdentity *my_identity)
164 * Remove experimentation request due to timeout
166 * @param cls the related node
167 * @param tc scheduler's task context
170 remove_request (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
172 struct Node *n = cls;
174 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Removing request for peer %s due to timeout\n"),
175 GNUNET_i2s (&n->id));
177 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (nodes_requested, &n->id.hashPubKey))
179 GNUNET_CONTAINER_multihashmap_remove (nodes_requested, &n->id.hashPubKey, n);
180 update_stats (nodes_requested);
181 GNUNET_CONTAINER_multihashmap_put (nodes_inactive, &n->id.hashPubKey, n,
182 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
183 update_stats (nodes_inactive);
186 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
189 GNUNET_CORE_notify_transmit_ready_cancel (n->cth);
196 * Core's transmit notify callback to send request
198 * @param cls the related node
199 * @param bufsize buffer size
200 * @param buf the buffer to copy to
201 * @return bytes passed
203 size_t send_experimentation_request_cb (void *cls, size_t bufsize, void *buf)
205 struct Node *n = cls;
206 struct Experimentation_Request msg;
207 size_t msg_size = sizeof (msg);
208 size_t ri_size = sizeof (struct Experimentation_Issuer) * GSE_my_issuer_count;
209 size_t total_size = msg_size + ri_size;
211 memset (buf, '0', bufsize);
215 /* client disconnected */
216 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client disconnected\n");
217 if (GNUNET_SCHEDULER_NO_TASK != n->timeout_task)
218 GNUNET_SCHEDULER_cancel (n->timeout_task);
219 GNUNET_SCHEDULER_add_now (&remove_request, n);
222 GNUNET_assert (bufsize >= total_size);
224 msg.msg.size = htons (total_size);
225 msg.msg.type = htons (GNUNET_MESSAGE_TYPE_EXPERIMENTATION_REQUEST);
226 msg.capabilities = htonl (GSE_node_capabilities);
227 msg.issuer_count = htonl (GSE_my_issuer_count);
228 memcpy (buf, &msg, msg_size);
229 memcpy (&((char *) buf)[msg_size], GSE_my_issuer, ri_size);
231 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Sending request to peer %s\n"),
232 GNUNET_i2s (&n->id));
238 * Send request to peer to start add him to to the set of experimentation nodes
240 * @param peer the peer to send to
242 static void send_experimentation_request (const struct GNUNET_PeerIdentity *peer)
248 c_issuers = GSE_my_issuer_count;
250 size = sizeof (struct Experimentation_Request) +
251 c_issuers * sizeof (struct Experimentation_Issuer);
252 n = GNUNET_malloc (sizeof (struct Node));
254 n->timeout_task = GNUNET_SCHEDULER_add_delayed (EXP_RESPONSE_TIMEOUT, &remove_request, n);
255 n->capabilities = NONE;
256 n->cth = GNUNET_CORE_notify_transmit_ready(ch, GNUNET_NO, 0,
257 GNUNET_TIME_relative_get_forever_(),
258 peer, size, send_experimentation_request_cb, n);
260 GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (nodes_requested,
261 &peer->hashPubKey, n, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
262 update_stats (nodes_requested);
267 * Core's transmit notify callback to send response
269 * @param cls the related node
270 * @param bufsize buffer size
271 * @param buf the buffer to copy to
272 * @return bytes passed
274 size_t send_response_cb (void *cls, size_t bufsize, void *buf)
276 struct Node *n = cls;
277 struct Experimentation_Response msg;
278 size_t ri_size = GSE_my_issuer_count * sizeof (struct Experimentation_Issuer);
279 size_t msg_size = sizeof (msg);
280 size_t total_size = msg_size + ri_size;
285 /* client disconnected */
286 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client disconnected\n");
289 GNUNET_assert (bufsize >= total_size);
291 msg.msg.size = htons (total_size);
292 msg.msg.type = htons (GNUNET_MESSAGE_TYPE_EXPERIMENTATION_RESPONSE);
293 msg.capabilities = htonl (GSE_node_capabilities);
294 msg.issuer_count = htonl (GSE_my_issuer_count);
295 memcpy (buf, &msg, msg_size);
296 memcpy (&((char *) buf)[msg_size], GSE_my_issuer, ri_size);
298 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Sending response to peer %s\n"),
299 GNUNET_i2s (&n->id));
305 get_experiments_cb (struct Node *n, struct Experiment *e)
307 static int counter = 0;
310 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Added %u experiments for peer %s\n"),
311 counter, GNUNET_i2s (&n->id));
315 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting experiment `%s' with peer %s\n"),
317 GNUNET_i2s (&n->id));
319 /* Tell the scheduler to add a node with an experiment */
320 GED_scheduler_add (n, e, GNUNET_YES);
325 get_node (const struct GNUNET_PeerIdentity *id)
332 tmp = GNUNET_CONTAINER_multihashmap_get (nodes_active, &id->hashPubKey);
336 tmp = GNUNET_CONTAINER_multihashmap_get (nodes_inactive, &id->hashPubKey);
340 GNUNET_break (0); /* Multiple instances */
342 tmp = GNUNET_CONTAINER_multihashmap_get (nodes_requested, &id->hashPubKey);
346 GNUNET_break (0); /* Multiple instances */
353 * Set a specific node as active
357 static void node_make_active (struct Node *n)
360 GNUNET_CONTAINER_multihashmap_put (nodes_active,
361 &n->id.hashPubKey, n, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
362 update_stats (nodes_active);
363 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Added peer `%s' as active node\n"),
364 GNUNET_i2s (&n->id));
366 /* Request experiments for this node to start them */
367 for (c1 = 0; c1 < n->issuer_count; c1++)
370 GED_experiments_get (n, &n->issuer_id[c1], &get_experiments_cb);
376 * Handle a request and send a response
378 * @param peer the source
379 * @param message the message
381 static void handle_request (const struct GNUNET_PeerIdentity *peer,
382 const struct GNUNET_MessageHeader *message)
385 struct Experimentation_Request *rm = (struct Experimentation_Request *) message;
386 struct Experimentation_Issuer *rmi = (struct Experimentation_Issuer *) &rm[1];
390 uint32_t ic_accepted;
393 if (ntohs (message->size) < sizeof (struct Experimentation_Request))
398 ic = ntohl (rm->issuer_count);
399 if (ntohs (message->size) != sizeof (struct Experimentation_Request) + ic * sizeof (struct Experimentation_Issuer))
405 make_active = GNUNET_NO;
406 if (NULL != (n = GNUNET_CONTAINER_multihashmap_get (nodes_active, &peer->hashPubKey)))
410 else if (NULL != (n = GNUNET_CONTAINER_multihashmap_get (nodes_requested, &peer->hashPubKey)))
412 GNUNET_CONTAINER_multihashmap_remove (nodes_requested, &peer->hashPubKey, n);
413 if (GNUNET_SCHEDULER_NO_TASK != n->timeout_task)
415 GNUNET_SCHEDULER_cancel (n->timeout_task);
416 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
420 GNUNET_CORE_notify_transmit_ready_cancel (n->cth);
423 update_stats (nodes_requested);
424 make_active = GNUNET_YES;
426 else if (NULL != (n = GNUNET_CONTAINER_multihashmap_get (nodes_inactive, &peer->hashPubKey)))
428 GNUNET_CONTAINER_multihashmap_remove (nodes_inactive, &peer->hashPubKey, n);
429 update_stats (nodes_inactive);
430 make_active = GNUNET_YES;
434 /* Create new node */
435 n = GNUNET_malloc (sizeof (struct Node));
437 n->capabilities = NONE;
438 make_active = GNUNET_YES;
442 n->capabilities = ntohl (rm->capabilities);
444 /* Filter accepted issuer */
446 for (c1 = 0; c1 < ic; c1++)
448 if (GNUNET_YES == GED_experiments_issuer_accepted(&rmi[c1].issuer_id))
451 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Request from peer `%s' with %u issuers, we accepted %u issuer \n"),
452 GNUNET_i2s (peer), ic, ic_accepted);
453 GNUNET_free_non_null (n->issuer_id);
454 n->issuer_id = GNUNET_malloc (ic_accepted * sizeof (struct GNUNET_PeerIdentity));
456 for (c1 = 0; c1 < ic; c1++)
458 if (GNUNET_YES == GED_experiments_issuer_accepted(&rmi[c1].issuer_id))
460 n->issuer_id[c2] = rmi[c1].issuer_id;
464 n->issuer_count = ic_accepted;
466 if (GNUNET_YES == make_active)
467 node_make_active (n);
470 n->cth = GNUNET_CORE_notify_transmit_ready (ch, GNUNET_NO, 0,
471 GNUNET_TIME_relative_get_forever_(),
473 sizeof (struct Experimentation_Response) +
474 GSE_my_issuer_count * sizeof (struct Experimentation_Issuer),
475 send_response_cb, n);
482 * @param peer the source
483 * @param message the message
485 static void handle_response (const struct GNUNET_PeerIdentity *peer,
486 const struct GNUNET_MessageHeader *message)
489 struct Experimentation_Response *rm = (struct Experimentation_Response *) message;
490 struct Experimentation_Issuer *rmi = (struct Experimentation_Issuer *) &rm[1];
492 uint32_t ic_accepted;
498 if (ntohs (message->size) < sizeof (struct Experimentation_Response))
503 ic = ntohl (rm->issuer_count);
504 if (ntohs (message->size) != sizeof (struct Experimentation_Response) + ic * sizeof (struct Experimentation_Issuer))
510 make_active = GNUNET_NO;
511 if (NULL != (n = GNUNET_CONTAINER_multihashmap_get (nodes_active, &peer->hashPubKey)))
513 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Received %s from %s peer `%s'\n"),
514 "RESPONSE", "active", GNUNET_i2s (peer));
516 else if (NULL != (n = GNUNET_CONTAINER_multihashmap_get (nodes_requested, &peer->hashPubKey)))
518 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Received %s from %s peer `%s'\n"),
519 "RESPONSE", "requested", GNUNET_i2s (peer));
520 GNUNET_CONTAINER_multihashmap_remove (nodes_requested, &peer->hashPubKey, n);
521 if (GNUNET_SCHEDULER_NO_TASK != n->timeout_task)
523 GNUNET_SCHEDULER_cancel (n->timeout_task);
524 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
528 GNUNET_CORE_notify_transmit_ready_cancel (n->cth);
531 update_stats (nodes_requested);
532 make_active = GNUNET_YES;
534 else if (NULL != (n = GNUNET_CONTAINER_multihashmap_get (nodes_inactive, &peer->hashPubKey)))
536 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Received %s from peer `%s'\n"),
537 "RESPONSE", "inactive", GNUNET_i2s (peer));
538 GNUNET_CONTAINER_multihashmap_remove (nodes_inactive, &peer->hashPubKey, n);
539 update_stats (nodes_inactive);
540 make_active = GNUNET_YES;
544 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Received %s from %s peer `%s'\n"),
545 "RESPONSE", "unknown", GNUNET_i2s (peer));
550 n->capabilities = ntohl (rm->capabilities);
552 /* Filter accepted issuer */
554 for (c1 = 0; c1 < ic; c1++)
556 if (GNUNET_YES == GED_experiments_issuer_accepted(&rmi[c1].issuer_id))
559 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Response from peer `%s' with %u issuers, we accepted %u issuer \n"),
560 GNUNET_i2s (peer), ic, ic_accepted);
561 GNUNET_free_non_null (n->issuer_id);
562 n->issuer_id = GNUNET_malloc (ic_accepted * sizeof (struct GNUNET_PeerIdentity));
564 for (c1 = 0; c1 < ic; c1++)
566 if (GNUNET_YES == GED_experiments_issuer_accepted(&rmi[c1].issuer_id))
568 n->issuer_id[c2] = rmi[c1].issuer_id;
572 n->issuer_count = ic_accepted;
574 if (GNUNET_YES == make_active)
575 node_make_active (n);
581 * @param peer the source
582 * @param message the message
584 static void handle_start (const struct GNUNET_PeerIdentity *peer,
585 const struct GNUNET_MessageHeader *message)
589 const struct GED_start_message *msg;
592 struct Experiment *e;
605 size = ntohs (message->size);
606 if (size < sizeof (struct GED_start_message))
611 msg = (const struct GED_start_message *) message;
612 name_len = ntohl (msg->len_name);
613 if (size != sizeof (struct GED_start_message) + name_len)
625 name = (const char *) &msg[1];
626 if (name[name_len-1] != '\0')
632 if (name_len != strlen (name) + 1)
638 e = GED_experiments_find (&msg->issuer, name, GNUNET_TIME_absolute_ntoh(msg->version_nbo));
645 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Received %s message from peer %s for experiment `%s'\n"),
646 "START", GNUNET_i2s (peer), name);
648 GED_scheduler_handle_start (n, e);
654 * @param peer the source
655 * @param message the message
657 static void handle_start_ack (const struct GNUNET_PeerIdentity *peer,
658 const struct GNUNET_MessageHeader *message)
662 const struct GED_start_ack_message *msg;
665 struct Experiment *e;
678 size = ntohs (message->size);
679 if (size < sizeof (struct GED_start_ack_message))
684 msg = (const struct GED_start_ack_message *) message;
685 name_len = ntohl (msg->len_name);
686 if (size != sizeof (struct GED_start_message) + name_len)
698 name = (const char *) &msg[1];
699 if (name[name_len-1] != '\0')
705 if (name_len != strlen (name) + 1)
711 e = GED_experiments_find (&msg->issuer, name, GNUNET_TIME_absolute_ntoh(msg->version_nbo));
718 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Received %s message from peer %s for experiment `%s'\n"),
719 "START_ACK", GNUNET_i2s (peer), name);
720 GED_scheduler_handle_start_ack (n, e);
726 * @param peer the source
727 * @param message the message
729 static void handle_stop (const struct GNUNET_PeerIdentity *peer,
730 const struct GNUNET_MessageHeader *message)
734 const struct GED_stop_message *msg;
737 struct Experiment *e;
750 size = ntohs (message->size);
751 if (size < sizeof (struct GED_stop_message))
756 msg = (const struct GED_stop_message *) message;
757 name_len = ntohl (msg->len_name);
758 if (size != sizeof (struct GED_start_message) + name_len)
770 name = (const char *) &msg[1];
771 if (name[name_len-1] != '\0')
777 if (name_len != strlen (name) + 1)
783 e = GED_experiments_find (&msg->issuer, name, GNUNET_TIME_absolute_ntoh(msg->version_nbo));
789 GED_scheduler_handle_stop (n, e);
793 * Method called whenever a given peer connects.
796 * @param peer peer identity this notification is about
798 void core_connect_handler (void *cls,
799 const struct GNUNET_PeerIdentity *peer)
801 if (GNUNET_YES == is_me(peer))
804 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connected to peer %s\n"),
807 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (nodes_requested, &peer->hashPubKey))
808 return; /* We already sent a request */
810 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (nodes_active, &peer->hashPubKey))
811 return; /* This peer is known as active */
813 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (nodes_inactive, &peer->hashPubKey))
814 return; /* This peer is known as inactive */
816 send_experimentation_request (peer);
822 * Method called whenever a given peer disconnects.
825 * @param peer peer identity this notification is about
827 void core_disconnect_handler (void *cls,
828 const struct GNUNET_PeerIdentity * peer)
830 if (GNUNET_YES == is_me(peer))
833 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Disconnected from peer %s\n"),
840 * Handle a request and send a response
843 * @param other the sender
844 * @param message the message
845 * @return GNUNET_OK to keep connection, GNUNET_SYSERR on error
848 core_receive_handler (void *cls,
849 const struct GNUNET_PeerIdentity *other,
850 const struct GNUNET_MessageHeader *message)
852 if (ntohs (message->size) < sizeof (struct GNUNET_MessageHeader))
855 return GNUNET_SYSERR;
858 switch (ntohs (message->type)) {
859 case GNUNET_MESSAGE_TYPE_EXPERIMENTATION_REQUEST:
860 handle_request (other, message);
862 case GNUNET_MESSAGE_TYPE_EXPERIMENTATION_RESPONSE:
863 handle_response (other, message);
865 case GNUNET_MESSAGE_TYPE_EXPERIMENTATION_START:
866 handle_start (other, message);
868 case GNUNET_MESSAGE_TYPE_EXPERIMENTATION_START_ACK:
869 handle_start_ack (other, message);
871 case GNUNET_MESSAGE_TYPE_EXPERIMENTATION_STOP:
872 handle_stop (other, message);
881 struct ExperimentStartCtx
883 struct ExperimentStartCtx *prev;
884 struct ExperimentStartCtx *next;
887 struct Experiment *e;
890 size_t node_experiment_start_cb (void *cls, size_t bufsize, void *buf)
892 struct ExperimentStartCtx *e_ctx = cls;
893 struct GED_start_message *msg;
897 GNUNET_CONTAINER_DLL_remove (e_ctx->n->e_req_head, e_ctx->n->e_req_tail, e_ctx);
898 e_ctx->n->cth = NULL;
905 name_len = strlen(e_ctx->e->name) + 1;
906 size = sizeof (struct GED_start_message) + name_len;
908 msg = GNUNET_malloc (size);
909 msg->header.size = htons (size);
910 msg->header.type = htons (GNUNET_MESSAGE_TYPE_EXPERIMENTATION_START);
911 msg->issuer = e_ctx->e->issuer;
912 msg->version_nbo = GNUNET_TIME_absolute_hton(e_ctx->e->version);
913 msg->len_name = htonl (name_len);
914 memcpy (&msg[1], e_ctx->e->name, name_len);
916 memcpy (buf, msg, size);
924 GED_nodes_rts (struct Node *n)
934 * Request a experiment to start with a node
936 * @return GNUNET_NO if core was busy with sending, GNUNET_OK otherwise
939 GED_nodes_request_start (struct Node *n, struct Experiment *e)
941 struct ExperimentStartCtx *e_ctx;
945 GNUNET_break (0); /* should call rts before */
949 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Sending experiment start request to peer `%s' for experiment `%s'\n"),
950 GNUNET_i2s(&n->id), e->name);
952 e_ctx = GNUNET_malloc (sizeof (struct ExperimentStartCtx));
955 n->cth = GNUNET_CORE_notify_transmit_ready (ch, GNUNET_NO, 0, FAST_TIMEOUT, &n->id,
956 sizeof (struct GED_start_message) + strlen (e->name) + 1,
957 &node_experiment_start_cb, e_ctx);
960 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Cannot send experiment start request to peer `%s' for experiment `%s'\n"),
961 GNUNET_i2s(&n->id), e->name);
964 GNUNET_CONTAINER_DLL_insert (n->e_req_head, n->e_req_tail, e_ctx);
971 * Start the nodes management
976 /* Connecting to core service to find partners */
977 ch = GNUNET_CORE_connect (GED_cfg, NULL,
978 &core_startup_handler,
979 &core_connect_handler,
980 &core_disconnect_handler,
981 &core_receive_handler,
982 GNUNET_NO, NULL, GNUNET_NO, NULL);
985 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Failed to connect to CORE service!\n"));
989 nodes_requested = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
990 nodes_active = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
991 nodes_inactive = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
996 * Stop the nodes management
1003 GNUNET_CORE_disconnect (ch);
1007 if (NULL != nodes_requested)
1009 GNUNET_CONTAINER_multihashmap_iterate (nodes_requested,
1012 update_stats (nodes_requested);
1013 GNUNET_CONTAINER_multihashmap_destroy (nodes_requested);
1014 nodes_requested = NULL;
1017 if (NULL != nodes_active)
1019 GNUNET_CONTAINER_multihashmap_iterate (nodes_active,
1022 update_stats (nodes_active);
1023 GNUNET_CONTAINER_multihashmap_destroy (nodes_active);
1024 nodes_active = NULL;
1027 if (NULL != nodes_inactive)
1029 GNUNET_CONTAINER_multihashmap_iterate (nodes_inactive,
1032 update_stats (nodes_inactive);
1033 GNUNET_CONTAINER_multihashmap_destroy (nodes_inactive);
1034 nodes_inactive = NULL;
1038 /* end of gnunet-daemon-experimentation_nodes.c */