2 This file is part of GNUnet
3 (C) 2008--2012 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 testbed/testbed_api_peers.c
23 * @brief management of the knowledge about peers in this library
24 * (we know the peer ID, its host, pending operations, etc.)
25 * @author Christian Grothoff
26 * @author Sree Harsha Totakura
30 #include "testbed_api_peers.h"
31 #include "testbed_api.h"
33 #include "testbed_api_hosts.h"
34 #include "testbed_api_operations.h"
40 static struct GNUNET_TESTBED_Peer *peer_list_head;
45 static struct GNUNET_TESTBED_Peer *peer_list_tail;
49 * Adds a peer to the peer list
51 * @param peer the peer to add to the peer list
54 GNUNET_TESTBED_peer_register_ (struct GNUNET_TESTBED_Peer *peer)
56 GNUNET_CONTAINER_DLL_insert_tail (peer_list_head, peer_list_tail, peer);
61 * Removes a peer from the peer list
63 * @param peer the peer to remove
66 GNUNET_TESTBED_peer_deregister_ (struct GNUNET_TESTBED_Peer *peer)
68 GNUNET_CONTAINER_DLL_remove (peer_list_head, peer_list_tail, peer);
76 GNUNET_TESTBED_cleanup_peers_ (void)
78 struct GNUNET_TESTBED_Peer *peer;
80 while (NULL != (peer = peer_list_head))
82 GNUNET_TESTBED_peer_deregister_ (peer);
90 * Function to call to start a peer_create type operation once all
91 * queues the operation is part of declare that the
92 * operation can be activated.
94 * @param cls the closure from GNUNET_TESTBED_operation_create_()
97 opstart_peer_create (void *cls)
99 struct OperationContext *opc = cls;
100 struct PeerCreateData *data;
101 struct GNUNET_TESTBED_PeerCreateMessage *msg;
108 GNUNET_assert (OP_PEER_CREATE == opc->type);
110 GNUNET_assert (NULL != data);
111 GNUNET_assert (NULL != data->peer);
112 opc->state = OPC_STATE_STARTED;
113 config = GNUNET_CONFIGURATION_serialize (data->cfg, &c_size);
114 xc_size = GNUNET_TESTBED_compress_config_ (config, c_size, &xconfig);
115 GNUNET_free (config);
116 msize = xc_size + sizeof (struct GNUNET_TESTBED_PeerCreateMessage);
117 msg = GNUNET_realloc (xconfig, msize);
118 memmove (&msg[1], msg, xc_size);
119 msg->header.size = htons (msize);
120 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER);
121 msg->operation_id = GNUNET_htonll (opc->id);
122 msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (data->peer->host));
123 msg->peer_id = htonl (data->peer->unique_id);
124 msg->config_size = htonl (c_size);
125 GNUNET_CONTAINER_DLL_insert_tail (opc->c->ocq_head, opc->c->ocq_tail, opc);
126 GNUNET_TESTBED_queue_message_ (opc->c, &msg->header);
131 * Callback which will be called when peer_create type operation is released
133 * @param cls the closure from GNUNET_TESTBED_operation_create_()
136 oprelease_peer_create (void *cls)
138 struct OperationContext *opc = cls;
142 case OPC_STATE_STARTED:
143 GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
144 /* No break we continue flow */
146 GNUNET_free (((struct PeerCreateData *) opc->data)->peer);
147 GNUNET_free (opc->data);
149 case OPC_STATE_FINISHED:
157 * Function called when a peer destroy operation is ready
159 * @param cls the closure from GNUNET_TESTBED_operation_create_()
162 opstart_peer_destroy (void *cls)
164 struct OperationContext *opc = cls;
165 struct GNUNET_TESTBED_Peer *peer;
166 struct GNUNET_TESTBED_PeerDestroyMessage *msg;
168 GNUNET_assert (OP_PEER_DESTROY == opc->type);
170 GNUNET_assert (NULL != peer);
171 opc->state = OPC_STATE_STARTED;
172 msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerDestroyMessage));
173 msg->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerDestroyMessage));
174 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_DESTROY_PEER);
175 msg->peer_id = htonl (peer->unique_id);
176 msg->operation_id = GNUNET_htonll (opc->id);
177 GNUNET_CONTAINER_DLL_insert_tail (opc->c->ocq_head, opc->c->ocq_tail, opc);
178 GNUNET_TESTBED_queue_message_ (peer->controller, &msg->header);
183 * Callback which will be called when peer_create type operation is released
185 * @param cls the closure from GNUNET_TESTBED_operation_create_()
188 oprelease_peer_destroy (void *cls)
190 struct OperationContext *opc = cls;
192 if (OPC_STATE_FINISHED != opc->state)
193 GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
199 * Function called when a peer start operation is ready
201 * @param cls the closure from GNUNET_TESTBED_operation_create_()
204 opstart_peer_start (void *cls)
206 struct OperationContext *opc = cls;
207 struct GNUNET_TESTBED_PeerStartMessage *msg;
208 struct PeerEventData *data;
209 struct GNUNET_TESTBED_Peer *peer;
211 GNUNET_assert (OP_PEER_START == opc->type);
212 GNUNET_assert (NULL != opc->data);
214 GNUNET_assert (NULL != data->peer);
216 GNUNET_assert ((PS_CREATED == peer->state) || (PS_STOPPED == peer->state));
217 opc->state = OPC_STATE_STARTED;
218 msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerStartMessage));
219 msg->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerStartMessage));
220 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_START_PEER);
221 msg->peer_id = htonl (peer->unique_id);
222 msg->operation_id = GNUNET_htonll (opc->id);
223 GNUNET_CONTAINER_DLL_insert_tail (opc->c->ocq_head, opc->c->ocq_tail, opc);
224 GNUNET_TESTBED_queue_message_ (peer->controller, &msg->header);
229 * Callback which will be called when peer start type operation is released
231 * @param cls the closure from GNUNET_TESTBED_operation_create_()
234 oprelease_peer_start (void *cls)
236 struct OperationContext *opc = cls;
238 if (OPC_STATE_FINISHED != opc->state)
240 GNUNET_free (opc->data);
241 GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
248 * Function called when a peer stop operation is ready
250 * @param cls the closure from GNUNET_TESTBED_operation_create_()
253 opstart_peer_stop (void *cls)
255 struct OperationContext *opc = cls;
256 struct GNUNET_TESTBED_PeerStopMessage *msg;
257 struct PeerEventData *data;
258 struct GNUNET_TESTBED_Peer *peer;
260 GNUNET_assert (NULL != opc->data);
262 GNUNET_assert (NULL != data->peer);
264 GNUNET_assert (PS_STARTED == peer->state);
265 opc->state = OPC_STATE_STARTED;
266 msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerStopMessage));
267 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER);
268 msg->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerStopMessage));
269 msg->peer_id = htonl (peer->unique_id);
270 msg->operation_id = GNUNET_htonll (opc->id);
271 GNUNET_CONTAINER_DLL_insert_tail (opc->c->ocq_head, opc->c->ocq_tail, opc);
272 GNUNET_TESTBED_queue_message_ (peer->controller, &msg->header);
277 * Callback which will be called when peer stop type operation is released
279 * @param cls the closure from GNUNET_TESTBED_operation_create_()
282 oprelease_peer_stop (void *cls)
284 struct OperationContext *opc = cls;
286 if (OPC_STATE_FINISHED != opc->state)
288 GNUNET_free (opc->data);
289 GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
296 * Generate PeerGetConfigurationMessage
298 * @param peer_id the id of the peer whose information we have to get
299 * @param operation_id the ip of the operation that should be represented in the
301 * @return the PeerGetConfigurationMessage
303 struct GNUNET_TESTBED_PeerGetConfigurationMessage *
304 GNUNET_TESTBED_generate_peergetconfig_msg_ (uint32_t peer_id,
305 uint64_t operation_id)
307 struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
310 GNUNET_malloc (sizeof
311 (struct GNUNET_TESTBED_PeerGetConfigurationMessage));
313 htons (sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage));
314 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_CONFIGURATION);
315 msg->peer_id = htonl (peer_id);
316 msg->operation_id = GNUNET_htonll (operation_id);
322 * Function called when a peer get information operation is ready
324 * @param cls the closure from GNUNET_TESTBED_operation_create_()
327 opstart_peer_getinfo (void *cls)
329 struct OperationContext *opc = cls;
330 struct PeerInfoData *data;
331 struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
334 GNUNET_assert (NULL != data);
335 opc->state = OPC_STATE_STARTED;
337 GNUNET_TESTBED_generate_peergetconfig_msg_ (data->peer->unique_id,
339 GNUNET_CONTAINER_DLL_insert_tail (opc->c->ocq_head, opc->c->ocq_tail, opc);
340 GNUNET_TESTBED_queue_message_ (opc->c, &msg->header);
345 * Callback which will be called when peer stop type operation is released
347 * @param cls the closure from GNUNET_TESTBED_operation_create_()
350 oprelease_peer_getinfo (void *cls)
352 struct OperationContext *opc = cls;
353 struct GNUNET_TESTBED_PeerInformation *data;
355 if (OPC_STATE_FINISHED != opc->state)
357 GNUNET_free_non_null (opc->data);
358 GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
363 GNUNET_assert (NULL != data);
366 case GNUNET_TESTBED_PIT_CONFIGURATION:
367 GNUNET_CONFIGURATION_destroy (data->result.cfg);
369 case GNUNET_TESTBED_PIT_IDENTITY:
370 GNUNET_free (data->result.id);
373 GNUNET_assert (0); /* We should never reach here */
382 * Function called when a overlay connect operation is ready
384 * @param cls the closure from GNUNET_TESTBED_operation_create_()
387 opstart_overlay_connect (void *cls)
389 struct OperationContext *opc = cls;
390 struct GNUNET_TESTBED_OverlayConnectMessage *msg;
391 struct OverlayConnectData *data;
393 opc->state = OPC_STATE_STARTED;
395 GNUNET_assert (NULL != data);
396 data->tslot_index = GNUNET_TESTBED_get_tslot_ (data->p1->host, data);
397 data->tstart = GNUNET_TIME_absolute_get ();
398 msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_OverlayConnectMessage));
400 htons (sizeof (struct GNUNET_TESTBED_OverlayConnectMessage));
401 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_OVERLAY_CONNECT);
402 msg->peer1 = htonl (data->p1->unique_id);
403 msg->peer2 = htonl (data->p2->unique_id);
404 msg->operation_id = GNUNET_htonll (opc->id);
405 msg->peer2_host_id = htonl (GNUNET_TESTBED_host_get_id_ (data->p2->host));
406 GNUNET_CONTAINER_DLL_insert_tail (opc->c->ocq_head, opc->c->ocq_tail, opc);
407 GNUNET_TESTBED_queue_message_ (opc->c, &msg->header);
412 * Callback which will be called when overlay connect operation is released
414 * @param cls the closure from GNUNET_TESTBED_operation_create_()
417 oprelease_overlay_connect (void *cls)
419 struct OperationContext *opc = cls;
420 struct GNUNET_TIME_Relative duration;
421 struct OverlayConnectData *data;
428 case OPC_STATE_STARTED:
429 (void) GNUNET_TESTBED_release_time_slot_ (data->p1->host, data->tslot_index,
431 GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
433 case OPC_STATE_FINISHED:
434 duration = GNUNET_TIME_absolute_get_duration (data->tstart);
435 GNUNET_TESTBED_update_time_slot_ (data->p1->host, data->tslot_index, data,
436 duration, data->failed);
444 * Lookup a peer by ID.
446 * @param id global peer ID assigned to the peer
447 * @return handle to the host, NULL on error
449 struct GNUNET_TESTBED_Peer *
450 GNUNET_TESTBED_peer_lookup_by_id_ (uint32_t id)
458 * Create the given peer at the specified host using the given
459 * controller. If the given controller is not running on the target
460 * host, it should find or create a controller at the target host and
461 * delegate creating the peer. Explicit delegation paths can be setup
462 * using 'GNUNET_TESTBED_controller_link'. If no explicit delegation
463 * path exists, a direct link with a subordinate controller is setup
464 * for the first delegated peer to a particular host; the subordinate
465 * controller is then destroyed once the last peer that was delegated
466 * to the remote host is stopped.
468 * Creating the peer only creates the handle to manipulate and further
469 * configure the peer; use "GNUNET_TESTBED_peer_start" and
470 * "GNUNET_TESTBED_peer_stop" to actually start/stop the peer's
473 * Note that the given configuration will be adjusted by the
474 * controller to avoid port/path conflicts with other peers.
475 * The "final" configuration can be obtained using
476 * 'GNUNET_TESTBED_peer_get_information'.
478 * @param controller controller process to use
479 * @param host host to run the peer on; cannot be NULL
480 * @param cfg Template configuration to use for the peer. Should exist until
481 * operation is cancelled or GNUNET_TESTBED_operation_done() is called
482 * @param cb the callback to call when the peer has been created
483 * @param cls the closure to the above callback
484 * @return the operation handle
486 struct GNUNET_TESTBED_Operation *
487 GNUNET_TESTBED_peer_create (struct GNUNET_TESTBED_Controller *controller,
488 struct GNUNET_TESTBED_Host *host,
489 const struct GNUNET_CONFIGURATION_Handle *cfg,
490 GNUNET_TESTBED_PeerCreateCallback cb, void *cls)
493 struct GNUNET_TESTBED_Peer *peer;
494 struct PeerCreateData *data;
495 struct OperationContext *opc;
496 static uint32_t id_gen;
498 peer = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Peer));
499 peer->controller = controller;
501 peer->unique_id = id_gen++;
502 peer->state = PS_INVALID;
503 data = GNUNET_malloc (sizeof (struct PeerCreateData));
509 opc = GNUNET_malloc (sizeof (struct OperationContext));
512 opc->id = GNUNET_TESTBED_get_next_op_id (controller);
513 opc->type = OP_PEER_CREATE;
515 GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_create,
516 &oprelease_peer_create);
517 GNUNET_TESTBED_operation_queue_insert_ (controller->opq_parallel_operations,
519 GNUNET_TESTBED_operation_begin_wait_ (opc->op);
525 * Start the given peer.
527 * @param op_cls the closure for this operation; will be set in
528 * event->details.operation_finished.op_cls when this operation fails.
529 * @param peer peer to start
530 * @param pcc function to call upon completion
531 * @param pcc_cls closure for 'pcc'
532 * @return handle to the operation
534 struct GNUNET_TESTBED_Operation *
535 GNUNET_TESTBED_peer_start (void *op_cls, struct GNUNET_TESTBED_Peer *peer,
536 GNUNET_TESTBED_PeerChurnCallback pcc, void *pcc_cls)
538 struct OperationContext *opc;
539 struct PeerEventData *data;
541 data = GNUNET_malloc (sizeof (struct PeerEventData));
544 data->pcc_cls = pcc_cls;
545 opc = GNUNET_malloc (sizeof (struct OperationContext));
546 opc->c = peer->controller;
548 opc->op_cls = op_cls;
549 opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
550 opc->type = OP_PEER_START;
552 GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_start,
553 &oprelease_peer_start);
554 GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
556 GNUNET_TESTBED_operation_begin_wait_ (opc->op);
562 * Stop the given peer. The handle remains valid (use
563 * "GNUNET_TESTBED_peer_destroy" to fully clean up the
564 * state of the peer).
566 * @param op_cls the closure for this operation; will be set in the event
568 * @param peer peer to stop
569 * @param pcc function to call upon completion
570 * @param pcc_cls closure for 'pcc'
571 * @return handle to the operation
573 struct GNUNET_TESTBED_Operation *
574 GNUNET_TESTBED_peer_stop (void *op_cls,
575 struct GNUNET_TESTBED_Peer *peer,
576 GNUNET_TESTBED_PeerChurnCallback pcc, void *pcc_cls)
578 struct OperationContext *opc;
579 struct PeerEventData *data;
581 data = GNUNET_malloc (sizeof (struct PeerEventData));
584 data->pcc_cls = pcc_cls;
585 opc = GNUNET_malloc (sizeof (struct OperationContext));
586 opc->c = peer->controller;
588 opc->op_cls = op_cls;
589 opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
590 opc->type = OP_PEER_STOP;
592 GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_stop,
593 &oprelease_peer_stop);
594 GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
596 GNUNET_TESTBED_operation_begin_wait_ (opc->op);
602 * Request information about a peer. The controller callback will not be called
603 * with event type GNUNET_TESTBED_ET_OPERATION_FINISHED when result for this
604 * operation is available. Instead, the GNUNET_TESTBED_PeerInfoCallback() will
607 * @param peer peer to request information about
608 * @param pit desired information
609 * @param cb the convenience callback to be called when results for this
610 * operation are available
611 * @param cb_cls the closure for the above callback
612 * @return handle to the operation
614 struct GNUNET_TESTBED_Operation *
615 GNUNET_TESTBED_peer_get_information (struct GNUNET_TESTBED_Peer *peer,
616 enum GNUNET_TESTBED_PeerInformationType
617 pit, GNUNET_TESTBED_PeerInfoCallback cb,
620 struct OperationContext *opc;
621 struct PeerInfoData *data;
623 GNUNET_assert (GNUNET_TESTBED_PIT_GENERIC != pit);
624 GNUNET_assert (NULL != cb);
625 data = GNUNET_malloc (sizeof (struct PeerInfoData));
629 data->cb_cls = cb_cls;
630 opc = GNUNET_malloc (sizeof (struct OperationContext));
631 opc->c = peer->controller;
633 opc->type = OP_PEER_INFO;
634 opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
636 GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_getinfo,
637 &oprelease_peer_getinfo);
638 GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
640 GNUNET_TESTBED_operation_begin_wait_ (opc->op);
646 * Change peer configuration. Must only be called while the
647 * peer is stopped. Ports and paths cannot be changed this
650 * @param peer peer to change configuration for
651 * @param cfg new configuration (differences to existing
652 * configuration only)
653 * @return handle to the operation
655 struct GNUNET_TESTBED_Operation *
656 GNUNET_TESTBED_peer_update_configuration (struct GNUNET_TESTBED_Peer *peer,
658 GNUNET_CONFIGURATION_Handle *cfg)
660 // FIXME: handle locally or delegate...
667 * Destroy the given peer; the peer should have been
668 * stopped first (if it was started).
670 * @param peer peer to stop
671 * @return handle to the operation
673 struct GNUNET_TESTBED_Operation *
674 GNUNET_TESTBED_peer_destroy (struct GNUNET_TESTBED_Peer *peer)
676 struct OperationContext *opc;
678 opc = GNUNET_malloc (sizeof (struct OperationContext));
680 opc->c = peer->controller;
681 opc->id = GNUNET_TESTBED_get_next_op_id (peer->controller);
682 opc->type = OP_PEER_DESTROY;
684 GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_destroy,
685 &oprelease_peer_destroy);
686 GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
688 GNUNET_TESTBED_operation_begin_wait_ (opc->op);
694 * Manipulate the P2P underlay topology by configuring a link
697 * @param op_cls closure argument to give with the operation event
698 * @param p1 first peer
699 * @param p2 second peer
700 * @param co option to change
701 * @param ... option-specific values
702 * @return handle to the operation, NULL if configuring the link at this
703 * time is not allowed
705 struct GNUNET_TESTBED_Operation *
706 GNUNET_TESTBED_underlay_configure_link (void *op_cls,
707 struct GNUNET_TESTBED_Peer *p1,
708 struct GNUNET_TESTBED_Peer *p2,
709 enum GNUNET_TESTBED_ConnectOption co,
718 * Both peers must have been started before calling this function.
719 * This function then obtains a HELLO from 'p1', gives it to 'p2'
720 * and asks 'p2' to connect to 'p1'.
722 * @param op_cls closure argument to give with the operation event
723 * @param cb the callback to call when this operation has finished
724 * @param cb_cls the closure for the above callback
725 * @param p1 first peer
726 * @param p2 second peer
727 * @return handle to the operation, NULL if connecting these two
728 * peers is fundamentally not possible at this time (peers
729 * not running or underlay disallows)
731 struct GNUNET_TESTBED_Operation *
732 GNUNET_TESTBED_overlay_connect (void *op_cls,
733 GNUNET_TESTBED_OperationCompletionCallback cb,
734 void *cb_cls, struct GNUNET_TESTBED_Peer *p1,
735 struct GNUNET_TESTBED_Peer *p2)
737 struct OperationContext *opc;
738 struct OverlayConnectData *data;
740 GNUNET_assert ((PS_STARTED == p1->state) && (PS_STARTED == p2->state));
741 data = GNUNET_malloc (sizeof (struct OverlayConnectData));
745 data->cb_cls = cb_cls;
746 opc = GNUNET_malloc (sizeof (struct OperationContext));
748 opc->c = p1->controller;
749 opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
750 opc->type = OP_OVERLAY_CONNECT;
751 opc->op_cls = op_cls;
753 GNUNET_TESTBED_operation_create_ (opc, &opstart_overlay_connect,
754 &oprelease_overlay_connect);
755 GNUNET_TESTBED_host_queue_oc_ (p1->host, opc->op);
756 GNUNET_TESTBED_operation_begin_wait_ (opc->op);
762 /* end of testbed_api_peers.c */